Token
创建Token
token创建时需要:
1. 签发时间:IssuedAt
2. 结束时间:ExpiresAt
3. 签发人:Issuer
4. token所携带的登录人信息(也就是可以表明是谁登录的)
其中,IssuedAt、ExpiresAt、Issuer可以写在jwt.StandardClaims中:
registeredClaims := jwt.RegisteredClaims{
ExpiresAt: expireTime.Unix(),
IssuedAt: time.Now().Unix(),
Issuer: "app",
}
之后加入登录人信息获得自定义Claims:
claims := UserClaims{
RegisteredClaims: registeredClaims,
UserName: name,
}
利用jwt.NewWithClaims(method SigningMethod, claims Claims) 函数获取Token类型的Token
其中SigningMethod为签名算法,jwt内置了许多算法,这里用的是jwt.SigningMethodHS256
claims参数为携带用户信息的自定义Claims
Token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
我们应向前端返回一个string类型的token,所以需要用SignedString方法签发
token, err := Token.SignedString(JwtKey)
其中JwtKey为我们自定义的一个btye切片,返回的token为string类型,我们将其发送到前端
c.JSON(http.StatusOK, gin.H{
"state": code,
"message": errmsg.GetErrMsg(code),
"token": token,
})
解析Token
后端接收来自前端的token字符串:tokenString,在判空后使用ParseWithClaims将其解析为Token类型的token
token, err := jwt.ParseWithClaims(tokenString, &UserClaims{}, func(token *jwt.Token) (interface{}, error) {
return JwtKey, nil
})
其中:
1. tokenString为string类型的token
2. &UserClaims{}为包含用户信息的自定义Claims
3. Keyfunc是一个返回值为JwtKey和error的函数
获取到Token类型的token后,断言token的claims为自定义的userclaims,并获取claims所携带的用户信息
if claims, ok := token.Claims.(*UserClaims); ok && token.Valid {
username = claims.UserName
err = nil
} else {
username = ""
err = errors.New("claims not UserClaims")
}
JWT中间件
jwt中间件主要功能为接收前端发送来的验证信息(Token)并将其中的用户信息解析出来,但在此项目中集成了用户的权限验证
token从前端以string的形式在请求头中传入后端,它对应的Key为Authorization(批准),在Authorization对应的值中Token是以 Bearer字符 + 空格 + Token 的格式储存的
首先让我们接收请求头的信息
// 获取验证信息(Token)
Authorization := c.Request.Header.Get("Authorization")
// 请求头是否有token
if Authorization == "" {
code = errmsg.INEXISTENCE_TOKEN
c.JSON(http.StatusOK, gin.H{
"state": code,
"message": errmsg.GetErrMsg(code),
})
c.Abort()
return
}
接收到请求头信息后我们验证是否为Token的格式(Bearer字符 + 空格 + Token )
由于其格式特殊,我们用字符串的 第一个空格将信息分为两段,前一段应为"Bearer",而后一段则为我们需要的Token字符串。
注:若信息不能以空格分为两端或者前一段不为"Bearer"则格式错误
// 检查token格式
Authorizations := strings.SplitN(Authorization, " ", 2)
if Authorizations[0] != "Bearer" || len(Authorizations) < 2 {
code = errmsg.TOKEN_TYPE_ERROR
c.JSON(http.StatusOK, gin.H{
"state": code,
"message": errmsg.GetErrMsg(code),
})
c.Abort()
return
}
获得string类型的Token后我们将其解析并获得用户信息,再用用户信息查询用户权限,最后检查用户权限是否充足
// 解析token
userName, err := JwtParseUser(Authorizations[1])
if err != nil {
code = errmsg.TOKEN_PARSE_ERROR
c.JSON(http.StatusOK, gin.H{
"state": code,
"message": errmsg.GetErrMsg(code),
})
c.Abort()
return
}
// 验证权限
ok := dao.ExamineRole(userName, role)
if !ok {
code = errmsg.INSUFFICIENT_ROLE
c.JSON(http.StatusOK, gin.H{
"state": code,
"message": errmsg.GetErrMsg(code),
})
c.Abort()
return
}
// 设置用户信息
c.Set("userName", userName)
c.Next()
essage": errmsg.GetErrMsg(code),
})
c.Abort()
return
}
// 设置用户信息
c.Set(“userName”, userName)
c.Next()