1)这里使用开源的 jwt-go

1.token 工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
package handler

import (
    "awesomeProject/utils"
    "github.com/dgrijalva/jwt-go"
    "github.com/gin-gonic/gin"
    "time"
)
//用户信息类,作为生成token的参数
type UserClaims struct {
    ID    string `json:"userId"`
    Name  string `json:"name"`
    Phone string `json:"phone"`
    //jwt-go提供的标注claim
    jwt.StandardClaims
}

var (
    //token秘钥
    secret = []byte("16849841325189456f487")
    //该路由下不校验token
    noVerify = []interface{}{"/login", "/ping"}
    //token有效时间(纳秒)
    effectTime = 2 * time.Hour
)

// 生成token
func GenerateToken(claims *UserClaims) string {
    //设置token有效期,也可不设置有效期,
    //将token存储在redis中,设置过期时间,如token如没过期,自动刷新redis过期时间,
    //通过这种方式,可以很方便的为token续期,而且也可以实现长时间不登录的话,强制登录
    claims.ExpiresAt = time.Now().Add(effectTime).Unix()
    //生成token
    sign, err := jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString(secret)
    if err != nil {
        //这里因为项目接入了统一异常处理,所以使用panic,如不接入,可使用原始方式
        //接入统一异常可参考 https://blog.csdn.net/u014155085/article/details/106733391
        panic(err)
    }
    return sign
}

//验证token
func JwtVerify(c *gin.Context) {
    //过滤是否验证token
    if utils.IsContainArr(noVerify, c.Request.RequestURI) {
        return
    }
    token := c.GetHeader("token")
    if token == "" {
        panic("token not exist !")
    }
    //验证token,并存储在请求中
    c.Set("user", parseToken(token))
}

// 解析Token
func parseToken(tokenString string) *UserClaims {
    //解析token
    token, err := jwt.ParseWithClaims(tokenString, &UserClaims{}, func(token *jwt.Token) (interface{}, error) {
        return secret, nil
    })
    if err != nil {
        panic(err)
    }
    claims, ok := token.Claims.(*UserClaims)
    if !ok {
        panic("token is valid")
    }
    return claims
}

// 更新token
func Refresh(tokenString string) string {
    jwt.TimeFunc = func() time.Time {
        return time.Unix(0, 0)
    }
    token, err := jwt.ParseWithClaims(tokenString, &UserClaims{}, func(token *jwt.Token) (interface{}, error) {
        return secret, nil
    })
    if err != nil {
        panic(err)
    }
    claims, ok := token.Claims.(*UserClaims)
    if !ok {
        panic("token is valid")
    }
    jwt.TimeFunc = time.Now
    claims.StandardClaims.ExpiresAt = time.Now().Add(2 * time.Hour).Unix()
    return GenerateToken(claims)
}

2. 使用该中间件

1
2
3
4
5
6
7
8
9
10
11
func main() {
    router := gin.Default()
    router.Use(handler.JwtVerify)

    router.GET("/ping", controller.Ping)
    router.GET("/login", controller.Login)
    router.GET("/userInfo", controller.UserInfo)

    router.Run(":8888") // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")

}

3. controller部分代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package controller

import (
    "awesomeProject/handler"
    "awesomeProject/utils"
    "github.com/dgrijalva/jwt-go"
    "github.com/gin-gonic/gin"
    "net/http"
)

func Ping(c *gin.Context) {
    c.JSON(http.StatusOK, utils.ResultT("this is ping"))
}

func Login(c *gin.Context) {
    c.JSON(http.StatusOK, utils.ResultT(gin.H{
        "token": handler.GenerateToken(&handler.UserClaims{
            ID:             "001",
            Name:           "张三",
            Phone:          "189***0023",
            StandardClaims: jwt.StandardClaims{},
        }),
    }))

}

func UserInfo(c *gin.Context) {
    user, _ := c.Get("user")
    claims := user.(*handler.UserClaims)
    c.JSON(http.StatusOK, utils.ResultT(claims.Phone))
}