inbox
getinfo 接口:
整体登陆-鉴权流程
-
/login接口,post,输入:用户名-密码-验证码-uuid,handler为LoginHandler
-
LoginHandler内部:
-
然后用户验证auth:jwtauth这个中间件实例化时传入的回调,Authenticator函数处理(用户名-密码-验证码-uuid)
- 从c中解析数据,bind到结构体实例中,通过后:
- 三方验证码库,根据uuid和code,进行校验,通过后:
- 根据username 用户名,查询用户名,获得user实例,查表
- 再根据user实例中的roleId,获得role的示例,查表
- 把user实例,role实例,组成一个map,返回该map
- 总结:验证用户名-密码-验证码,通过后,查表取到该用户对应的user实例、role实例,组成map,然后返回,这里map假设变量为data 其结构: {"user": user实例, "role" : role实例}
-
实例化一个空的token实例,以及一个空的claims容器:类型map[string]interface (借助jwt三方库)
-
payloadFunc,负载数据挂入(也是jwtauth中间件实例化时传入的回调)
- 接收一个interface{}空接口类型,即可接收任意类型,(实际业务代码传入的auth函数中处理得到的data数据,是个map,
- 先对data进行类型断言:data.(map[string]interface{})
- 根据user这个key,取出user实例,类型断言
- 根据role这个key,取出role实例,类型断言
- 从user、role实例取出一些字段,组成一个map数据并返回,类型map[string]interface{},具体内容如下:
{ "identity": user类型实例模型的UserId int类型 "roleid" : role类型实例的 RoleId int类型 "rolekey": role类型实例的 RoleKey string 角色代码、描述符,比如admin、devlop "nice": user类型实例的 UserName 字段 string "nickName": user类型实例的 Nickname 字段 string "datascope": role类型实例的 DataScope字段 string "rolename": role类型实例的 RoleName 字段 string } -
payloadFunc()调用得到返回的map,然后进行遍历,key、value分别填充到上文空的claims这个map中
-
claims,再添加2组键值对,“exp”和“orig_iat” ,分别表示下一次过期的时间点,和这次token的生成时间
-
借助jwt库,把填充了实际数据claim的token,转换为token字符串此时token字符串,就包含了上述的7个字段信息
-
如果还配置了,setCookie选项,则把token字符串,组成cookie,也发到cookie里一份
-
响应客户端,主要内容就是token字符串
-
鉴权中间件(对所有需要鉴权的接口生效)
- 先从c对象中取出token字符串(这里假设只考虑token在http的头部传入的情况)
- 得到的token字符串,再有jwt三方库解析为*jwt.token对象
- 实例化一个空的map容器,map[string]interface{}类型
- 再从token对象中取出Claims数据(map),进行遍历,添加到claims这个空的map容器中, 此时claims的数据应该如下:
{
"identity": user类型实例模型的UserId int类型
"roleid" : role类型实例的 RoleId int类型
"rolekey": role类型实例的 RoleKey string 角色代码、描述符,比如admin、devlop
"nice": user类型实例的 UserName 字段 string
"nickName": user类型实例的 Nickname 字段 string
"datascope": role类型实例的 DataScope字段 string
"rolename": role类型实例的 RoleName 字段 string
"exp": 过期时间点
"orig_iat": token生成时间点
}
-
判断claims中的exp字段,是否为空、格式是否正确、是否过期,全部验证通过后!
-
把claims数据,挂载到c对象上,字段为:"JWT_PAYLOAD",值是map,(之后的handler,只需要c.Get("JWT_PAYLOAD") 即可访问到claims这个map,进而得到它的9个字段信息,”JWT_PAYLOAD“ 的标识符为 JwtPayloadKey
-
调用函数IdentityHandler()也是jwtauth中间件实例化时传入的回调,
- 从c中抽取claims信息,就是通过c.Get(JwtPayloadKey)获得的,得到全部9个字段的map
- 然后再从完整的map中,抽取身份鉴权相关的6个字段,组成一个新的map,如下:
return map[string]interface{}{ "IdentityKey": claims["identity"], # 对应原:user实例的UserId int 类型 "UserName": claims["nice"], "RoleKey": claims["rolekey"], "UserId": claims["identity"], # 对应原:user实例和UserId int类型 "RoleIds": claims["roleid"], "DataScope": claims["datascope"], }- 返回所组成的新的map,
-
然后把IdentityHandler返回的新的map映射,也挂载到c实例上 c.Set(IdentityKey, 新map)IdentityKey是字符串”identity“的标识符 6.注意:此时:c实例上有个key,”JWT_PAYLOAD“ 对应的值为 完整的claim信息,如下图数据1; 第二个key ”identity“ 它对应的值为 下图数据2
# 数据1:
map[string]interface{}{
"identity": user类型实例模型的UserId int类型
"roleid" : role类型实例的 RoleId int类型
"rolekey": role类型实例的 RoleKey string 角色代码、描述符,比如admin、devlop
"nice": user类型实例的 UserName 字段 string
"nickName": user类型实例的 Nickname 字段 string
"datascope": role类型实例的 DataScope字段 string
"rolename": role类型实例的 RoleName 字段 string
"exp": 过期时间点
"orig_iat": token生成时间点
}
# 数据2:
map[string]interface{}{
"IdentityKey": claims["identity"], # 对应原:user实例的UserId int 类型
"UserName": claims["nice"],
"RoleKey": claims["rolekey"],
"UserId": claims["identity"], # 对应原:user实例和UserId int类型
"RoleIds": claims["roleid"],
"DataScope": claims["datascope"],
}
9.最后一步鉴权:authorizator ,也是jwtauth 中间件实例化时,传入的回调,这里懵了!——传入的回调如下:但是代码里,data的实参为上一步的identity 的返回的新map,样式是(数据2),哪里来的user和role的 key?
// 自定义鉴权的hook,但是哪里体现鉴权了QA
func Authorizator(data interface{}, c *gin.Context) bool {
if v, ok := data.(map[string]interface{}); ok {
u, _ := v["user"].(models.SysUser)
r, _ := v["role"].(models.SysRole)
c.Set("role", r.RoleName)
c.Set("roleIds", r.RoleId)
c.Set("userId", u.UserId)
c.Set("userName", u.UserName)
c.Set("nickName", u.NickName)
c.Set("dataScope", r.DataScope)
return true
}
return false
}