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()
    }
}
上一篇 下一篇

猜你喜欢

热点阅读