什么是JMT?什么是gtoken?
JWT(JSON Web Token)和gtoken都是用于用户认证和授权的技术;token 是一串字符串,通常因为作为鉴权凭据。
二者区别
1.实现方式: JWT是一种标准和规范,有多种语言的实现;gtoken是GoFrame框架的特定组件,专为GoFrame设计
2.存储方式: JWT通常是无状态的,服务器不需要存储token;gtoken支持将token存储在内存或Redis中,便于管理和控制
3.功能扩展: gtoken提供了更多GoFrame生态的便捷功能,如多端登录控制、自动续期等;JWT更加轻量,但需要自己实现一些额外功能 4.使用场景: JWT适合跨服务、跨平台的认证场景;gtoken更适合GoFrame框架内的项目,提供更便捷的集成体验
在项目的应用
gtoken是一个基于GoFrame框架的令牌管理和身份验证中间件,它是用于GoFrame框架的一个第三方扩展包,由goflyfox开发,主要用于处理用户登录认证和授权。从代码中可以看到,项目(goframe-shop-v2)使用了github.com/goflyfox/gtoken v1.5.7这个版本。简单来说,gtoken就像是一个门卫,负责检查访问系统的人是否有合法的"通行证"(token)。
1. 分离前后台认证系统
项目中使用了两套gtoken认证系统:
- 管理后台认证:通过StartBackendGToken()函数初始化,用于管理员登录和后台管理
- 前台用户认证:通过StartFrontendGToken()函数初始化,用于普通用户登录和前台操作

2. 登录验证流程
gtoken的登录验证流程如下:
(1)登录前验证:
- 后台使用loginFunc函数

loginFunc 用于处理登录请求,从请求中获取用户名和密码,并进行简单的非空校验。如果验证不通过,则立即返回错误响应; 上下文(ctx)的使用:context.TODO() 是一个占位,提示后续可能需要根据业务需求换成合适的上下文;退出机制:当用户名或密码缺失时,通过返回 JSON 错误信息并调用 r.ExitAll() 终止请求中的其他处理工作。 TODO 注释:是一个常见的编程标记,用于提示开发者代码中未完成或有待改进的部分。在其它代码位置,它提醒团队或未来的你需要去掉或优化全局校验逻辑。
- 前台使用loginFuncFrontend函数

这两个函数负责验证用户名和密码,查询数据库确认用户身份
(2)登录成功后的处理:
- 后台使用loginAfterFunc函数
func
if !respData.Success() {
respData.Code = 0
r.Response.WriteJson(respData)
return
} else {
respData.Code = 1
//获得登录用户id
userKey := respData.GetString("userKey")
adminId := gstr.StrEx(userKey, consts.GTokenAdminPrefix)
//根据id获得登录用户其他信息
adminInfo := entity.AdminInfo{}
err := dao.AdminInfo.Ctx(context.TODO()).WherePri(adminId).Scan(&adminInfo)
if err != nil {
return
}
//通过角色查询权限
//先通过角色查询权限id
var rolePermissionInfos []entity.RolePermissionInfo
err = dao.RolePermissionInfo.Ctx(context.TODO()).WhereIn(dao.RolePermissionInfo.Columns().RoleId, g.Slice{adminInfo.RoleIds}).Scan(&rolePermissionInfos)
if err != nil {
return
}
permissionIds := g.Slice{}
for _, info := range rolePermissionInfos {
permissionIds = append(permissionIds, info.PermissionId)
}
var permissions []entity.PermissionInfo
err = dao.PermissionInfo.Ctx(context.TODO()).WhereIn(dao.PermissionInfo.Columns().Id, permissionIds).Scan(&permissions)
if err != nil {
return
}
data := &backend.LoginRes{
Type: consts.TokenType,
Token: respData.GetString("token"),
ExpireIn: consts.GTokenExpireIn, //单位秒,
IsAdmin: adminInfo.IsAdmin,
RoleIds: adminInfo.RoleIds,
Permissions: permissions,
}
response.JsonExit(r, 0, "", data)
}
return
}
- 前台使用loginAfterFuncFrontend函数
//
func loginAfterFuncFrontend(r *ghttp.Request, respData gtoken.Resp) {
if !respData.Success() {
respData.Code = 0
r.Response.WriteJson(respData)
return
} else {
respData.Code = 1
//获得登录用户id
userKey := respData.GetString("userKey")
userId := gstr.StrEx(userKey, consts.GTokenFrontendPrefix)
//根据id获得登录用户其他信息
userInfo := entity.UserInfo{}
err := dao.UserInfo.Ctx(context.TODO()).WherePri(userId).Scan(&userInfo)
if err != nil {
return
}
data := &frontend.LoginRes{
Type: consts.TokenType,
Token: respData.GetString("token"),
ExpireIn: consts.GTokenExpireIn, //单位秒,
}
data.Name = userInfo.Name
data.Avatar = userInfo.Avatar
data.Sign = userInfo.Sign
data.Status = uint8(userInfo.Status)
response.JsonExit(r, 0, "", data)
}
return
}
这些函数在登录成功后生成token并返回给客户端,同时会查询用户的附加信息(如权限列表)
(3)鉴权后的处理:
- 后台使用authAfterFunc函数

- 前台使用authAfterFuncFrontend函数
这些函数负责在每次请求验证token后,将用户信息设置到请求上下文中
3. 路由保护
在cmd.go中,可以看到gtoken被用于保护需要登录才能访问的路由:

使用gtoken达到的作用:
1. 安全性保障
项目使用gtoken主要是为了保障用户信息安全,具体体现在:
-
请求验证:确保只有登录用户才能访问敏感接口
-
权限控制:管理员登录后,会查询其角色和对应的权限列表
-
密码安全:登录时密码经过加密处理,不以明文形式出现
-
过期机制:token有效期设置为10天,过期后需要重新登录
2. 提高用户体验
-
保持登录状态:用户无需频繁登录
-
多端登录支持:允许用户在多个设备上同时登录
-
前后台分离:前台用户和管理员使用不同的认证系统,互不影响
3. 优化系统架构
-
中间件方式:以中间件形式集成,代码侵入性小
-
缓存使用:使用Redis缓存token信息,提高验证速度
-
统一认证:所有需要认证的接口通过同一机制处理,代码更加统一和简洁
4. 身份信息传递
-
登录后将用户ID、用户名等重要信息设置到请求上下文
-
在后续处理中,控制器可以方便地获取当前登录用户的信息
-
例如:r.SetCtxVar(consts.CtxUserId, userInfo.Id)使得用户ID可以在整个请求处理流程中被获取