golang jwt鉴权分析
2020-06-11 本文已影响0人
jojo1313
技术栈 gin+jwt
鉴权流程:
调用token生成方法GenerateToken生成token, 请求api时带上token参数即可
token计算逻辑:
总结:md5加密账号和密码参数,根据账号密码私钥过期时间和jwt header 分别计算hash256值,将值用.符号连接,再进行hash,结果就是token值
1. 分别对username password 计算md5值返回摘要,作为十六进制数据字符串值
2.过期时间 int64
3.私钥 string
4.分别对Header和Claims格式化成json后使用EncodeSegment加密然后用“.”符号jion连接起来
Header=map[alg:HS256 typ:JWT]
type Claims struct {
Username string `json:"username"`
Password string `json:"password"`
Audience string `json:"aud,omitempty"`
ExpiresAt int64 `json:"exp,omitempty"`
Id string `json:"jti,omitempty"`
IssuedAt int64 `json:"iat,omitempty"`
Issuer string `json:"iss,omitempty"`
NotBefore int64 `json:"nbf,omitempty"`
Subject string `json:"sub,omitempty"`
}
5.jion字符串使用hmac.New()进行hash ,结果就是token值
import (
"github.com/dgrijalva/jwt-go"
)
type Claims struct {
Username string `json:"username"`
Password string `json:"password"`
jwt.StandardClaims
}
//token生成
func GenerateToken(username, password string) (string, error) {
nowTime := time.Now()
expireTime := nowTime.Add(3 * time.Minute) //过期时间取值
claims := Claims{
EncodeMD5(username),//md5值返回摘要,作为十六进制数据字符串值
EncodeMD5(password),//md5值返回摘要,作为十六进制数据字符串值
jwt.StandardClaims{
ExpiresAt: expireTime.Unix(),//过期时间 int64
Issuer: "abcdefg",//私钥 string
},
}
//token 逆向解析代码
//主要使用jwt.ParseWithClaims方法
func ParseToken(token string) (*Claims, error) {
tokenClaims, err := jwt.ParseWithClaims(token, &Claims{}, func(token *jwt.Token) (interface{}, error) {
return jwtSecret, nil
})
if tokenClaims != nil {
if claims, ok := tokenClaims.Claims.(*Claims); ok && tokenClaims.Valid {
return claims, nil
}
}
return nil, err
}
//生成token 主要使用 jwt.NewWithClaims和tokenClaims.SignedString实现
tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
token, err := tokenClaims.SignedString(jwtSecret)
return token, err
}
api 验证token:
import (
"github.com/gin-gonic/gin"
"github.com/xxxxx/middleware/jwt"
"github.com/xxxxx/routers/api"
)
func InitRouter() *gin.Engine{
r := gin.New()
//ginpprof.Wrap(r) //pprof 性能分析
r.Use(gin.Logger())
r.Use(gin.Recovery())
lvsapi := r.Group("/api/")
lvsapi.Use(jwt.JWT()) // 在这里url入口启用JWT鉴权
//JWT()是自己写的方法,是一个类似闭包的形式中间件return func(c *gin.Context){c.Next()}
{
lvsapi.POST("/v111", api.V111)
}
return r
}
func JWT() gin.HandlerFunc {
return func(c *gin.Context) {
var code int
var data interface{}
code = e.SUCCESS
token := c.Query("token")
if token == "" {
code = e.INVALID_PARAMS
} else {
_, err := util.ParseToken(token) //验证token
if err != nil {
switch err.(*jwt.ValidationError).Errors {
case jwt.ValidationErrorExpired:
code = e.ERROR_AUTH_CHECK_TOKEN_TIMEOUT
default:
code = e.ERROR_AUTH_CHECK_TOKEN_FAIL
}
}
}
if code != e.SUCCESS {
c.JSON(http.StatusUnauthorized, gin.H{
"code": code,
"msg": e.GetMsg(code),
"data": data,
})
c.Abort()
return
}
c.Next()
}
}