如何在go里使用jwt(包含示例)

什么是JWT

JWT就是一种基于Token的轻量级认证模式,服务端认证通过后,会生成一个JSON对象,经过签名后得到一个Token(令牌)再发回给用户,用户后续请求只需要带上这个Token,服务端解密之后就能获取该用户的相关信息了。

版本信息

go:1.22.3
github.com/golang-jwt/jwt/v5 v5.2.1
github.com/jinzhu/gorm v1.9.16
开启了mod模式

使用示例

创建vue目录,go mod init vue,创建midware文件夹,下面创建文件jwt.go,内容如下:

package midware

import (
	"errors"
	"net/http"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt/v5"
)

// CustomClaims 自定义声明类型 并内嵌jwt.RegisteredClaims
// jwt包自带的jwt.RegisteredClaims只包含了官方字段
// 假设我们这里需要额外记录一个username字段,所以要自定义结构体
// 如果想要保存更多信息,都可以添加到这个结构体中
type CustomClaims struct {
	// 可根据需要自行添加字段
	Username string `json:"username"`
	Password string `json:"password"`
	jwt.RegisteredClaims        // 内嵌标准的声明
}

var CustomSecret = []byte("djsahkdasduowjbnckauwna")
 
// GenToken 生成JWT
func GenToken(password, username string) (string, error) {
	// 创建一个我们自己声明的数据
	claims := CustomClaims{
		password,
		username, // 自定义字段
		jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24)),	// 定义过期时间
			Issuer:    "somebody", // 签发人
		},
	}
	
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	// 生成签名字符串
	return token.SignedString(CustomSecret)
}

func ParseToken(tokenString string) (*CustomClaims, error) {
	// 解析token
	var mc = new(CustomClaims)
	token, err := jwt.ParseWithClaims(tokenString, mc, func(token *jwt.Token) (i interface{}, err error) {
		return CustomSecret, nil
	})
	if err != nil {
		return nil, err
	}
	// 对token对象中的Claim进行类型断言
	if token.Valid { // 校验token
		return mc, nil
	}
	return nil, errors.New("invalid token")
}

func JWTAuthMiddleware() func(c *gin.Context) {
	return func(c *gin.Context) {
		//获取到请求头中的token
		authHeader := c.Request.Header.Get("Authorization")
		if authHeader == "" {
			c.JSON(http.StatusOK, gin.H{
				"Msg":  "请求头中的auth为空!",
				"Data": nil,
			})
			c.Abort()
			return
		}
		// 按空格分割
		parts := strings.SplitN(authHeader, " ", 2)
		if !(len(parts) == 2 && parts[0] == "Bearer") {
			c.JSON(http.StatusOK, gin.H{
				"Msg":  "请求头中的auth格式错误",
				"Data": nil,
			})
			c.Abort()
			return
		}
		// parts[1]是获取到的tokenString,我们使用之前定义好的解析JWT的函数来解析它
		mc, err := ParseToken(parts[1])
		if err != nil {
			c.JSON(http.StatusOK, gin.H{
				"Msg":  "访问失败,无效的token,请登录!",
				"Data": nil,
			})
			c.Abort()
			return
		}
		// 将当前请求的userID信息保存到请求的上下文c上
		c.Set("Username", mc.Username)
		c.Next() // 后续的处理函数可以用过c.Get("username")来获取当前请求的用户信息
	}
}

然后在vue目录下创建main.go,如下

package main

import (
	"fmt"
	"time"
	"vue/midware"  //导入jwt中间件

	gincors "github.com/gin-contrib/cors"
	"github.com/gin-gonic/gin"
	gorm "github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/mysql"
)
type UserInfo struct {
	gorm.Model
	User string
	Email string
}

func main() {
	router := gin.Default()
	// 设置跨域 CORS 中间件
	router.Use(gincors.New(gincors.Config{
		AllowAllOrigins:  true, // 允许所有源
		AllowMethods:     []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
		AllowHeaders:     []string{"Origin", "Content-Length", "Content-Type", "Authorization"},
		ExposeHeaders:    []string{"Content-Length"},
		AllowCredentials: true,
		MaxAge:           12 * time.Hour,
	}))

	// 设置登录路由
	router.POST("/login", loginHandler)
	// submit添加中间件验证,这种方式中间件添加方式,中间件要放到Headler函数的前面
	router.POST("/submit", midware.JWTAuthMiddleware(), submitHeadler)
	router.Run(":8080")
}
// loginHandler 处理登录请求
func loginHandler(c *gin.Context) {
	var loginData struct {
		Username string `json:"username"`
		Password string `json:"password"`
	}
	// 从请求体中绑定 JSON 数据
	if err := c.ShouldBindJSON(&loginData); err != nil {
		c.JSON(400, gin.H{"success": false, "message": "Invalid request payload"})
		return
	}
	// 检查用户名和密码。测试方便先这样写,可以放到数据库里查询对比
	if loginData.Username == "admin" && loginData.Password == "secret" {
		token, err := midware.GenToken(loginData.Password, loginData.Username)
		if err != nil {
			c.JSON(200, gin.H{"success": true, "message": "Gen Token error", "token": token})
		}else {
			c.JSON(200, gin.H{"success": true, "message": "Login successful.", "token": token})
		}
	} else {
		c.JSON(401, gin.H{"success": false, "message": "Invalid username or password."})
	}
}
// 通过接受到的数据写到后端数据库里
func submitHeadler(c *gin.Context) {
	fmt.Println("----提交请求----")
	var submitData struct {
		Name string `json:"name"`
		Email string `json:"email"`
	}
	// 从请求体中绑定 JSON 数据
	if err := c.ShouldBindJSON(&submitData); err != nil {
		c.JSON(400, gin.H{"success": false, "message": "Invalid request payload"})
		return
	}
	name := submitData.Name
	email := submitData.Email
	// 链接数据库
	db, err := gorm.Open("mysql", "root:root@tcp(10.204.121.68:3306)/app?charset=utf8mb4&parseTime=True&loc=Local")
	if err != nil {
		panic("failed to connect database")
	}
	defer db.Close()
	db.AutoMigrate(&UserInfo{})
	db.Create(&UserInfo{
		User: name,
		Email: email,
	})
}

运行效果测试

1、运行main.go,先通过login获取token,如下图
login api
2、把上一步获取的token放到Headers里,如下图,要记得加上Bearer,格式是Bearer token
header设置:
submit api
body设置:
在这里插入图片描述
3、点击Send后,可以到数据库查看是否已写入。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值