Go + Gin实现双Token管理员登录的示例代码
作者:Go Dgg
本文主要介绍了Go + Gin实现双Token管理员登录的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
一、为什么要做「双 Token」
传统单 Token(JWT)架构下,“续签”与“强制失效” 是一对矛盾:
单 Token 痛点 | 双 Token 解法 |
---|---|
Token 过期后需重新登录,体验差 | Access-Token 失效后,用 Refresh-Token 无感刷新 |
Token 一旦泄露,在有效期内无法撤销 | Refresh-Token 存 Redis,可一键踢人 |
续签逻辑侵入业务代码 | 续签、校验、踢人全部封装在 Auth 中间件 |
本文将用 Gin + GORM + Redis 带你落地一套生产可用的「管理员双 Token」登录体系。
二、整体架构
┌────────────┐ ┌──────────────┐ ┌──────────┐ │ Web │──────►│ Handler │──────►│ Logic │ └────────────┘ └──────────────┘ └──────────┘ ▲ ▲ │ │ │ ▼ │ ┌──────────────┐ ┌──────────┐ │ │ Response │ │ Repo │ └────────────┘ Helper │ └──────────┘ │ Redis / MySQL
- Handler 负责参数校验、鉴权前置检查
- Logic 处理核心业务:登录、刷新、退出、获取用户信息
- Repo 封装数据访问:MySQL 查管理员、Redis 存 Refresh-Token
- Response 统一封装返回格式,避免样板代码
三、核心代码走读
3.1 路由层(Handler)
// NewAdminLoginHandler 管理员登录 func NewAdminLoginHandler() gin.HandlerFunc { return func(c *gin.Context) { var req requests.AdminLoginReq if err := c.ShouldBindJSON(&req); err != nil { response.Fail(c, "参数不合法") return } repo := repositories.NewAdminLoginRepository(globals.DB, globals.RDB) logic := logics.NewAdminLoginLogic(repo) resp, err := logic.Login(c.Request.Context(), &req) if err != nil { response.Fail(c, fmt.Sprintf("登录失败: %v", err)) return } response.OK(c, "登录成功", resp) } }
- 只做「绑定参数 + 调用逻辑 + 包装返回」
- 不掺杂任何业务判断,保持 单一职责
3.2 业务层(Logic)
3.2.1 登录
func (l *AdminLoginLogic) Login(ctx context.Context, req *requests.AdminLoginReq) (*responses.AdminLoginResp, error) { admin, err := l.findAdminByAccount(ctx, req.Account) if err != nil || admin == nil { return nil, errors.New("账号不存在") } if admin.Status != 1 { return nil, errors.New("账号已被禁用") } if !usersignutil.CheckPasswordHash(req.Password, admin.Password) { return nil, errors.New("密码错误") } // 更新最后登录时间 _ = l.adminRepo.UpdateLastLoginTime(ctx, admin.ID) // 生成双 Token return l.generateTokensAndBuildResponse(ctx, admin) }
3.2.2 生成双 Token
func (l *AdminLoginLogic) generateTokensAndBuildResponse( ctx context.Context, admin *models.Admin, ) (*responses.AdminLoginResp, error) { accessToken, _ := usersignutil.GenerateAccessToken(admin.ID) refreshToken, _ := usersignutil.GenerateRefreshToken(admin.ID) // 保存 Refresh-Token 到 Redis,设置过期时间 err := l.adminRepo.SaveRefreshToken( ctx, admin.ID, refreshToken, globals.AppConfig.JWT.RefreshTokenExpiry, ) if err != nil { // 记录日志但不阻断登录 globals.Log.Error("SaveRefreshToken err:", err) } resp := (&responses.AdminLoginResp{}).ToResponse(admin) resp.AccessToken = accessToken resp.RefreshToken = refreshToken return resp, nil }
3.2.3 获取管理员信息
func (l *AdminLoginLogic) GetAdminInfo(ctx context.Context, adminID uint) (*responses.AdminInfoResp, error) { admin, err := l.adminRepo.FindByIDWithDetails(ctx, adminID) if err != nil || admin == nil { return nil, errors.New("管理员不存在") } if admin.Status != 1 { return nil, errors.New("账号已被禁用") } return (&responses.AdminInfoResp{}).ToResponse(admin), nil }
3.2.4 登出
func (l *AdminLoginLogic) Logout(ctx context.Context, adminID uint) error { return l.adminRepo.DeleteRefreshToken(ctx, adminID) }
3.3 数据访问层(Repo)
仅展示关键函数,完整代码已在文章开头给出。
FindByPhone / FindByAccountID / FindByIDWithDetails
利用 GORM 的Preload
一把连表查,减少 N+1SaveRefreshToken / DeleteRefreshToken
使用admin:refresh_token:{id}
作为 Redis Key,天然支持「单设备登录」或「多端互踢」
四、如何无感刷新 Access-Token
前端收到 401 Unauthorized
后,携带 Refresh-Token 调 /admin/refresh
:
// 伪代码(Handler 略) refreshToken := c.GetHeader("X-Refresh-Token") adminID, err := usersignutil.ParseRefreshToken(refreshToken) if err != nil { /* 无效 Refresh-Token */ } // 与 Redis 比对 saved, _ := repo.GetRefreshToken(ctx, adminID) if saved != refreshToken { /* 已被踢出 */ } // 重新颁发 newAccess, _ := usersignutil.GenerateAccessToken(adminID)
五、安全细节
细节 | 实现 |
---|---|
密码加密 | bcrypt 哈希,不可逆 |
Token 签名 | 使用独立 jwtSecret ,区分 Access/Refresh |
Refresh-Token 存储 | Redis + TTL,支持热踢人 |
SQL 注入 | GORM 占位符自动防注入 |
并发登录 | Redis Key 覆盖即可实现「后者踢前者」 |
六、总结
本文用 200 行核心代码展示了:
- 分层架构:Handler → Logic → Repo
- 双 Token:Access-Token(短)+ Refresh-Token(长)
- 统一响应:封装
response.OK / Fail
消除样板 - 安全退出:Redis 删除 Refresh-Token 即踢人
到此这篇关于Go + Gin实现双Token管理员登录的示例代码的文章就介绍到这了,更多相关Go Gin 双Token管理员登录内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!