ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Gin框架使用jwt-go配合中间件认证

2022-03-04 04:31:17  阅读:282  来源: 互联网

标签:code 中间件 jwt token go gin password gindemo


参考文档

// 文档
https://github.com/golang-jwt/jwt
https://pkg.go.dev/github.com/golang-jwt/jwt@v3.2.2+incompatible#example-NewWithClaims-CustomClaimsType
https://gin-gonic.com/zh-cn/docs/examples/using-middleware/
https://gin-gonic.com/zh-cn/docs/examples/custom-middleware/

下载

// 下载
go get -u github.com/golang-jwt/jwt

实战

// util/jwt.go
package util

import (
	"gindemo/pkg/setting"
	"time"

	"github.com/golang-jwt/jwt"
)

var jwtSecret = []byte(setting.JwtSecret) //配置文件中自己配置的

// Claims是一些用户信息状态和额外的jwt参数
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(time.Minute * 15).Unix()

	claims := Claims{
		Username: username,
		Password: password,
		StandardClaims: jwt.StandardClaims{
			ExpiresAt: expireTime, // 过期时间
			Issuer:    "gindemo",  //指定发行人
		},
	}
	// 该方法内部生成签名字符串,再用于获取完整、已签名的token
	tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	token, err := tokenClaims.SignedString(jwtSecret)
	return token, err
}

// 根据传入的token值获取到Claims对象信息(进而获取其中的用户名和密码)
func ParseToken(token string) (*Claims, error) {
	// 用于解析鉴权的声明,方法内部主要是具体的解码和校验的过程,最终返回*Token
	tokenClaims, err := jwt.ParseWithClaims(token, &Claims{}, func(token *jwt.Token) (interface{}, error) {
		return jwtSecret, nil
	})
	if tokenClaims != nil {
		// 从tokenClaims中获取到Claims对象,并使用断言,将该对象转换为我们自己定义的Claims
		// 要传入指针,项目结构体都是用指针传递,节省空间
		if claims, ok := tokenClaims.Claims.(*Claims); ok && tokenClaims.Valid { // Valid()验证基于时间的声明
			return claims, nil
		}
	}
	return nil, err
}



// 中间件
// middleware/jwt/jwt.go
package jwt

import (
	"gindemo/pkg/e"
	"gindemo/pkg/util"
	"net/http"
	"time"

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

// 自定义中间件
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 {
                        // 解析token
			claims, err := util.ParseToken(token)
			if err != nil {
				code = e.ERROR_AUTH_CHECK_TOKEN_FAIL
			} else if time.Now().Unix() > claims.ExpiresAt {
				code = e.ERROR_AUTH_CHECK_TOKEN_TIMEOUT
			}
		}
		if code != e.SUCCESS {
			c.JSON(http.StatusUnauthorized, gin.H{
				"code": code,
				"msg":  e.GetMsg(code),
				"data": data,
			})
			c.Abort()
			return
		}
		c.Next()
	}
}


// models/auth.go
// 数据库查用户
package models

type Auth struct {
	ID       int    `gorm:"primary_key" json:"id"`
	Username string `json:"username"`
	Password string `json:"password"`
}

func CheckAuth(username, password string) bool {
	var auth Auth
	db.Select("id").Where(Auth{Username: username, Password: password}).First(&auth)
	return auth.ID > 0
}


// routers/api/auth.go
// 用户认证逻辑视图
package api

import (
	"gindemo/models"
	"gindemo/pkg/e"
	"gindemo/pkg/util"
	"log"
	"net/http"

	"github.com/astaxie/beego/validation"
	"github.com/gin-gonic/gin"
)

type auth struct {
	Username string `valid:"Required;MaxSize(50)"`
	Password string `valid:"Required;MaxSize(50)"`
}

func GetAuth(c *gin.Context) {
	username := c.Query("username")
	password := c.Query("password")

	valid := validation.Validation{}

	a := auth{Username: username, Password: password}
	ok, _ := valid.Valid(&a)

	data := make(map[string]interface{})
	code := e.INVALID_PARAMS
	if ok {
        // 去数据库中查询用户是否存在
		isExist := models.CheckAuth(username, password)
		if isExist {
            // 创建token
			token, err := util.GenerateToken(username, password)
			if err != nil {
				code = e.ERROR_AUTH_TOKEN
			} else {
				data["token"] = token
				code = e.SUCCESS
			}
		} else {
			code = e.ERROR_AUTH
		}
	} else {
		for _, err := range valid.Errors {
			log.Println(err.Key, err.Message)
		}
	}

	c.JSON(http.StatusOK, gin.H{
		"code": code,
		"msg":  e.GetMsg(code),
		"data": data,
	})
}


// routers/router.go
// 添加auth路由
package routers

import (
	"gindemo/middleware/jwt"
	"gindemo/pkg/setting"
	"gindemo/routers/api"
	v1 "gindemo/routers/api/v1"

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

func InitRouter() *gin.Engine {
	r := gin.New()

	r.Use(gin.Logger())
	r.Use(gin.Recovery())
	gin.SetMode(setting.RunMode)

	// 认证
	r.GET("/auth", api.GetAuth)

	// 路由组
	apiv1 := r.Group("/api/v1")
	{
		...
	}

	return r
}


// 测试
http://127.0.0.1:8000/auth?username=test&password=test123456
// 返回数据
{
    "code": 200,
    "data": {
        "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InRlc3QiLCJwYXNzd29yZCI6InRlc3QxMjM0NTYiLCJleHAiOjE2NDYzMzc0NzMsImlzcyI6ImdpbmRlbW8ifQ.mFGXb6dyYFGIni3joNinfpsNmeDAvvDOFKSfvJ4ss1w"
    },
    "msg": "ok"
}



// 将中间件接入Gin
// routers/router.go
package routers

import (
	"gindemo/middleware/jwt"
	"gindemo/pkg/setting"
	"gindemo/routers/api"
	v1 "gindemo/routers/api/v1"

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

func InitRouter() *gin.Engine {
	r := gin.New()

	r.Use(gin.Logger())
	r.Use(gin.Recovery())
	gin.SetMode(setting.RunMode)

	// 认证
	r.GET("/auth", api.GetAuth)

	// 路由组
	apiv1 := r.Group("/api/v1")
	// 使用中间件认证
	apiv1.Use(jwt.JWT())
    
	{
		...
	}

	return r
}


// 以后每次请求的时候先获取Token,然后请求其他url的时候带上token就可以了

标签:code,中间件,jwt,token,go,gin,password,gindemo
来源: https://www.cnblogs.com/weiweivip666/p/15962739.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有