Gin中使用jwt:发放token、中间件鉴权


Gin中使用jwt:发放token、中间件鉴权

jwt,github地址:

https://github.com/dgrijalva/jwt-go/

前端返回结果的token分析:

//eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VySWQiOjYsImV4cCI6MTYzNzY2Nzk5OCwiaWF0IjoxNjM3MDYzMTk4LCJpc3MiOiJjaGVuZ3FpYW5nIiwic3ViIjoidXNlciB0b2tlbiJ9.nt8K7vxrAT4XXzh0RbtFveQCyt7J4r1XZnVgDNSVjkQ
//token由三部分组成
//加密协议、荷载(程序信息)、前面两部分+自定义密匙组成的一个哈希值
//使用base64解密保存的信息(分三段进行解密) :  echo eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 | base64 -D

jwt配置:common/jwt.go

package common

import (
	"github.com/dgrijalva/jwt-go"
	"supplierQuerySystemAPICode/model"
	"time"
)

//定义秘钥
var jwtKey = []byte("*******")

type Claims struct {
	UserId uint
	jwt.StandardClaims
}

//登录成功之后发放token
func ReleaseToken(user model.User) (string, error) {
	expirationTime := time.Now().Add(7 * 24 * time.Hour) //token的有效期是七天
	claims := &Claims{
		UserId: user.ID,
		StandardClaims: jwt.StandardClaims{
			ExpiresAt: expirationTime.Unix(), //token的有效期
			IssuedAt:  time.Now().Unix(), //token发放的时间
			Issuer:    "chengqiang", //作者
			Subject:   "user token", //主题
		},
	}

	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	tokenString, err := token.SignedString(jwtKey) //根据前面自定义的jwt秘钥生成token

	if err != nil {
		//返回生成的错误
		return "", err
	}
	//返回成功生成的字符换
	return tokenString, nil
}
//eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VySWQiOjYsImV4cCI6MTYzNzY2Nzk5OCwiaWF0IjoxNjM3MDYzMTk4LCJpc3MiOiJjaGVuZ3FpYW5nIiwic3ViIjoidXNlciB0b2tlbiJ9.nt8K7vxrAT4XXzh0RbtFveQCyt7J4r1XZnVgDNSVjkQ
//token由三部分组成
//加密协议、荷载(程序信息)、前面两部分+自定义密匙组成的一个哈希值
//使用base64解密保存的信息(分三段进行解密) :  echo eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 | base64 -D



//解析从前端获取到的token值
func ParseToken(tokenString string) (*jwt.Token, *Claims, error) {
	claims := &Claims{}
	token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
		return jwtKey, nil
	})
	return token, claims, err
}

中间件判断前端获取的请求信息,验证通过,获取用户信息id,存入上下文中

package middleware

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"strings"
	"supplierQuerySystemAPICode/common"
	"supplierQuerySystemAPICode/model"
)
//路由请求中间件,前端必须把token放在请求头上,对服务器进行请求验证token成功后,才能访问后续的请求路由
func AuthMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 获取 authorization header:获取前端传过来的信息的
		tokenString := c.GetHeader("Authorization")

		fmt.Print("请求token", tokenString)

		//验证前端传过来的token格式,不为空,开头为Bearer
		if tokenString == "" || !strings.HasPrefix(tokenString, "Bearer ") {
			c.JSON(401, gin.H{
				"data": gin.H{

				},
				"meta": gin.H{
					"msg":  "权限不足",
					"code": 401,
				},
			})
			return
		}

		//验证通过,提取有效部分(除去Bearer)
		tokenString = tokenString[7:] //截取字符
		//解析token:common/jwt.go
		token, claims, err := common.ParseToken(tokenString)
		//解析失败||解析后的token无效
		if err != nil || !token.Valid {
			c.JSON(401, gin.H{
				"data": gin.H{

				},
				"meta": gin.H{
					"msg":  "权限不足",
					"code": 401,
				},
			})
			return
		}

		//token通过验证, 获取claims中的UserID
		userId := claims.UserId
		var user model.User
		//查询数据库
		common.DB.First(&user, userId)

		// 验证用户是否存在
		if user.ID == 0 {
			c.JSON(401, gin.H{
				"data": gin.H{

				},
				"meta": gin.H{
					"msg":  "权限不足",
					"code": 401,
				},
			})
		}

		//用户存在 将user信息写入上下文
		c.Set("user", user)

		c.Next()
	}
}