JWT中间件的使用
什么是JWT?
JWT全称JSON Web Token是一种跨域认证解决方案,属于一个开放的标准,它规定了一种Token 实现方式,目前多用于前后端分离项目的场景下。
为什么需要JWT?
在之前的一些web项目中,我们通常使用的是Cookie-Session模式实现用户认证。相关流程大致如下:用户在浏览器端填写用户名和密码,并发送给服务端服务端对用户名和密码校验通过后会生成一份保存当前用户相关信息的session数据和一个与之对应的标识(通常称为session_id)服务端返回响应时将上一步的session_id写入用户浏览器的Cookie后续用户来自该浏览器的每次请求都会自动携带包含session_id的Cookie服务端通过请求中的session_id就能找到之前保存的该用户那份session数据,从而获取该用户的相关信息。这种方案依赖于客户端(浏览器)保存 Cookie,并且需要在服务端存储用户的session数据。如果用户禁用了Cookie这种方法则不能使用,并且在这种情况下用户在一个网站登录如果访问同公司的另一家网站自动登录无法实现。于是乎采用Token验证的JWT方式应运而生。
在golang中使用
引入相关库
go get github.com/golang-jwt/jwt/v5使用这个JWT相关库来实现JWT和解析JWT的功能
自定义claim
通过两个自定义的user_id和username来自定义claim 在解析token时可以通过这个自定义的claim来获得user_id和username 来进行操作 type CustomClaims struct { UserID int64 `json:"user_id"` Username string `json:"username"` jwt.RegisteredClaims }这里我使用了两个字段
设置密钥
这里设置了密钥来进行生成token密钥 var CustomSecret = []byte("nihaoChina")
生成JWT
func MakeToken(username string, userId int64) (string, error) { claims := CustomClaims{ userId, username, jwt.RegisteredClaims{ Issuer: "my-project", ExpiresAt: jwt.NewNumericDate(time.Now().Add(TokenExpireDuration)), }, } token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) return token.SignedString(CustomSecret) }
解析JWT
func ParseNewToken(tokenString string) (*CustomClaims, error) { token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (i interface{}, err error) { return CustomSecret, nil }) if err != nil { return nil, err } if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid { return claims, nil } return nil, errors.New("invalid token") }通过上诉使用即可在程序中使用JWT
在gin框架中使用
创建一个JWT中间件这里面是根据自定义的claim生成的中间件其中通过c.set() 可以传递获取的user_id来进行校验 package middlewares import ( "WebApp/api" new2 "WebApp/pkg/jwt" "net/http" "strings" "github.com/gin-gonic/gin" ) func JWTAuthMiddleware() func(c *gin.Context) { return func(c *gin.Context) { authHeader := c.Request.Header.Get("Authorization") if authHeader == "" { api.ResponseError(c, api.CodeNeedLogin) c.Abort() return } parts := strings.SplitN(authHeader, " ", 2) if !(len(parts) == 2 && parts[0] == "Bearer") { api.ResponseError(c, api.CodeInvalideToken) c.Abort() return } mc, err := new2.ParseNewToken(parts[1]) if err != nil { c.JSON(http.StatusOK, gin.H{ "code": 2005, "msg": "无效的Token", }) c.Abort() return } c.Set(api.ContextUserNamekey, mc.Username) c.Set(api.ContextUserIdKey, mc.UserID) c.Next() } }在gin框架中通过使用中间件的方式来进行token的验证 r.GET("/home", middlewares.JWTAuthMiddleware(), api.HomeHandler) func HomeHandler(c *gin.Context) { username := GetCurrentUsername(c) c.JSON(http.StatusOK, gin.H{ "code": 2000, "msg": "success", "data": gin.H{"username": username}, }) }验证成功返回相对应的id信息,通过此来进行JWT的认证