go-gin 实现jwt中间件

236 阅读2分钟

第一步安装jwt

go get github.com/dgrijalva/jwt-go

第二步编写jwt.go 中间件文件

package middleware

import (
	"strings"
	"time"
	"webgin/utils"
	"webgin/utils/errmsg"
	"webgin/utils/msgjson"

	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
)
/*
    这里的utils.JwtKey 我用uuid插件生成的e9a62e0d-d520-465f-8188-c3e7b13977bd
*/
var JwtKey = []byte(utils.JwtKey)

// MyClaims 结构表示 JWT 中的声明
type MyClaims struct {
	Username string `json:"username"`
	jwt.StandardClaims
}

// SetToken 生成 JWT Token 并返回
func SetToken(username string) (string, int) {
	// 设置 Token 过期时间为 24 小时
	expireTime := time.Now().Add(time.Hour * 24).Unix()
	// 创建自定义声明结构
	claims := MyClaims{
		username,
		jwt.StandardClaims{
			ExpiresAt: expireTime, // 过期时间
			Issuer:    "xwya",
		},
	}
	// 使用 HS256 签名算法创建 Token
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	// 签名 Token 并返回
	tokenString, err := token.SignedString(JwtKey)
	if err != nil {
		return "", errmsg.Error
	}
	return tokenString, errmsg.Success
}

// CheckToken 验证 JWT Token 并返回声明
func CheckToken(tokenString string) *MyClaims {
	// 解析 Token 并验证签名
	token, err := jwt.ParseWithClaims(tokenString, &MyClaims{}, func(token *jwt.Token) (interface{}, error) {
		return JwtKey, nil
	})
	// token.Valid 判断token是否是有效值

	// 处理解析和验证错误
	if err != nil || err == jwt.ErrSignatureInvalid || !token.Valid {
		return nil // Token 格式错误
	}

	// 检查 Token 是否有效并返回声明
	claims, _ := token.Claims.(*MyClaims)

	return claims
}

// jwt中间件
func JwtToken() gin.HandlerFunc {
	return func(c *gin.Context) {
		token := c.GetHeader("Authorization")
		if token == "" {
			msgjson.ErrorMsg(c, errmsg.GetErrMsg(errmsg.Error_TokenExist)) // token 错误
			c.Abort()
			return
		}
		// 将 Token 头分成两部分,"Bearer" 和 Token 字符串
		checkToken := strings.SplitN(token, " ", 2)
		if len(checkToken) != 2 && checkToken[0] != "Bearer" {
			msgjson.ErrorMsg(c, errmsg.GetErrMsg(errmsg.Error_TokenMalformed)) // token 格式错误
			c.Abort()
			return
		}
		// 验证 Token 并获取声明
		key := CheckToken(checkToken[1])
		if key == nil {
			msgjson.ErrorMsg(c, errmsg.GetErrMsg(errmsg.Error_TokenInvalid)) // token 无效
			c.Abort()
			return
		}
		// 检查 Token 是否已过期
		if time.Now().Unix() > key.ExpiresAt {
			msgjson.ErrorMsg(c, errmsg.GetErrMsg(errmsg.Error_TokenTimeout)) // token 过期
			c.Abort()
			return
		}
		// 将声明中的用户名添加到上下文中
		c.Set("username", key.Username)
		c.Next()
	}
}

第三步 加入使用的路由组

package route

import (
	con "webgin/api/v1"
	"webgin/middleware"
	"webgin/utils"
	"webgin/utils/validator"

	"github.com/gin-gonic/gin"
)

// 初始化路由
func InitRoute() {
	gin.SetMode(utils.AppMode)
	// 初始化路由
	r := gin.Default()
	// 初始化翻译器
	validator.InitValidate()
	r.Use(middleware.InitLogger())
	router := r.Group("/api")
	// 后台登录接口模块
	{
		adminLoginRoute := router.Group("/adminlogin")
		{
			// 后台登录
			adminLoginRoute.POST("/login", con.AdminLogin)
			// // 后台退出登录
			// adminLoginRoute.POST("/logout", con.AdminLogout)
			// // 后台获取用户信息
			// adminLoginRoute.GET("/getAdminUserInfo", con.GetAdminUserInfo)
			// // 后台获取用户列表
		}
	}

	// 后台用户路由模块
	{
		adminUserRoute := router.Group("/adminuser")
		// adminUserRoute.Use(middleware.JwtToken())
		{
			// 添加后台用户
			adminUserRoute.POST("/addAdminUser", con.AddAdminUser)
			// 删除后台用户
			adminUserRoute.POST("/oddAdminUser", con.OddAdminUser)
			// 修改后台用户密码
			adminUserRoute.POST("/EditPassword", con.EditAdminUserPassword)
			// 修改后台用户权限
			adminUserRoute.POST("/EditAdminRole", con.EditAdminUserAuthority)
			// 获取后台用户列表
			adminUserRoute.GET("/getAdminUserList/:pageNum/:pageSize", con.GetAdminUserList)
			// 获取用户信息
			adminUserRoute.GET("/getAdminUserInfo/:id", con.GetAdminUserInfo)
		}
	}
        	r.Run(utils.Prot)
}


第四步编写登录接口 实现settoken

控制层代码

package controller

import (
	"webgin/model"
	msgjson "webgin/utils/msgjson"

	m "webgin/middleware"

	"github.com/gin-gonic/gin"
)

// 登录接口
func AdminLogin(c *gin.Context) {
	var userInfo map[string]string
	c.BindJSON(&userInfo)

	// 查询用户是否存在
	res := model.GetAdminUser(userInfo["username"])
	if res == "" {
		msgjson.ErrorMsg(c, "用户不存在请联系管理员")
		return
	}
	// 去登录
	username, err := model.AdminLogin(userInfo["username"], userInfo["password"])
	if err != nil || username == "" {
		c.Set("err", err.Error())
		msgjson.ErrorMsg(c, "用户名或密码错误")
		return
	}
	// 添加token
	token, code := m.SetToken(username)
	if code == 200 {
		msgjson.LoginMsg(c, "登录成功", token)
	} else {
		msgjson.ErrorMsg(c, "登录失败")
	}
}

服务层代码

// 查询用户是否存在
func GetAdminUser(username string) string {
	var user AdminUser
	db.Select("id").Where(" username = ?", username).First(&user)
	if user.ID > 0 {
		return errmsg.GetErrMsg(errmsg.Error_UserExist)
	}
	return ""
}
// 登录接口
func AdminLogin(username, password string) (string, error) {
	var user AdminUser
	tx := db.Begin()
	if err := tx.Model(&AdminUser{}).Where("username = ? and password = ?", username, cryptor.HmacMd5(utils.PassPrefix, password)).First(&user).Error; err != nil {
		tx.Rollback()
		return "", err
	}
	if err := tx.Commit().Error; err != nil {
		tx.Rollback()
		return "", err
	}
	return user.Username, nil
}