前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Go实现Jwt登录验证

Go实现Jwt登录验证

原创
作者头像
陈杪秋
发布2024-07-02 21:46:12
220
发布2024-07-02 21:46:12

前言

本文将带你了解如何使用Golang实现Jwt登录验证即实现一个jwt的token签发以及中间件验证方法。

关于jwt有关的知识点可以参考阮一峰的博客,此处不再赘述。

如果想使用jwt解析器可以到Jwt官方网站

如果你想学习Go以及上线一个简单的网盘项目,欢迎学习或者参与进我的开源项目Go-Cloud-Disk。如果能给我的项目点一个star更好不过,你的鼓励与点赞会使得我的项目和博客变得更好!

环境配置

使用到的Go包

Gin:本文将使用Gin进行路由注册。官方教程

Go-jwt: golang使用jwt的包。官方教程

代码语言:go
复制
go get -u github.com/golang-jwt/jwt/v5
go get -u github.com/gin-gonic/gin

如何签发token?

生成token

代码语言:go
复制
package main

import (
	"errors"
	"time"

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

// 填写你的jwt密钥
var jwtKey = "23333333333"

// jwt中存储的信息
type MyClaims struct {
	// 你想要往jwt中存储的信息,这里简单存储用户id,名称
	UserId   string `json:"user_id"`
	UserName string `json:"user_name"`
	jwt.RegisteredClaims // 一定要包含该Client
}

// User 用户信息示例
type User struct {
	UserId   string
	UserName string
}

// GenToken 根据传入的用户信息生成一个jwt密钥
// issuer 一般填写签发人员
// expireHour 填写有效时间,小时制
func GenToken(issuer string, expireHour int, user User) (string, error) {
	mySigningKey := []byte(jwtKey)
	claims := MyClaims{
		UserId:   user.UserId,
		UserName: user.UserName,
		RegisteredClaims: jwt.RegisteredClaims{
			Issuer:    issuer,                                                                    // 填入签发者
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Duration(expireHour) * time.Hour)), // 填写到期时间
			IssuedAt:  jwt.NewNumericDate(time.Now()),                                            // 填写签发时间
		},
	}
	// 根据选择的加密方式生成jwt密钥
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

	return token.SignedString(mySigningKey)
}

调用对应函数

代码语言:go
复制
package main

import "fmt"

func main() {
	userInfo := User{
		UserId:   "66666",
		UserName: "miaoqiu",
	}

	token, err := GenToken("miaoqiu", 24, userInfo)
	if err != nil {
		return
	}
	fmt.Println(token)
}

输出

代码语言:cmd
复制
PS C:\Users\Admin\Desktop\Go\go-jwt-learn> go build 
PS C:\Users\Admin\Desktop\Go\go-jwt-learn> .\learn.exe
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiNjY2NjYiLCJ1c2VyX25hbWUiOiJtaWFvcWl1IiwiaXNzIjoibWlhb3FpdSIsImV4cCI6MTcyMDAxMjI3OSwiaWF0IjoxNzE5OTI1ODc5fQ.Dz7WJY-jvo1P-epsz6EQcR1p1mrv6AH-4tUXVYy7k4U

到官网解析一下token

成功签发!!!

注意,可以从官网解析中发现,jwt为默认明文传输,请不要存放敏感信息,如果要存放敏感信息可以用密钥再加密一次。

解析token

golang解析token函数,

代码语言:go
复制
func ParseToken(tokenString string) (*MyClaims, error) {
	mySigningKey := []byte(jwtKey) //填入自己存放的jwt密钥
	token, err := jwt.ParseWithClaims(tokenString, &MyClaims{}, func(t *jwt.Token) (interface{}, error) {
		return mySigningKey, nil
	})
	if err != nil {
		return nil, err
	}
	if claims, ok := token.Claims.(*MyClaims); ok && token.Valid {
		return claims, nil
	}
	return nil, errors.New("tokenErr")
}

Gin框架鉴权中间件实现

代码语言:go
复制
package main

import (
	"strings"
	"time"

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

func JWTAuth() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 存放token一般都是在请求头部的Authorization按该格式存放"Bearer [token]"
		authorization := c.Request.Header.Get("Authorization")
		if authorization == "" {
			c.JSON(200, "NeedToken")
			c.Abort()
			return
		}
		// 由于"Bearer [token]"中间存在空格直接切分即可
		parts := strings.Split(authorization, " ")
		// 判断格式是否正确
		if len(parts) != 2 || parts[0] != "Bearer" {
			c.JSON(200, "TokenFormatErr")
			c.Abort()
			return
		}

		// 解析token
		claims, err := ParseToken(parts[1])
		if err != nil {
			c.JSON(200, "TokenErr")
			c.Abort()
			return
		}

		// 判断是否过期
		if time.Now().Unix() > claims.ExpiresAt.Unix() {
			c.JSON(200, "TokenExpiration")
			c.Abort()
			return
		}

		// 向context中存放信息
		c.Set("UserId", claims.UserId)
		c.Set("UserName", claims.UserName)

		// 获取信息可以使用
		// userId := c.MustGet("UserId").(string)

		c.Next()
	}
}

该如何使用?

登录接口示例

代码语言:go
复制
// Login check username and password can matched
// and return user info and jwt token
func (service *UserLoginService) Login(c *gin.Context) serializer.Response {
	// 校验具体账号密码是否正确.......

    // 签发token
	token, err := utils.GenToken("miaoqiu", 24, &user)
	if err != nil {
		return serializer.InternalErr("GetTokenErr", err)
	}

    // 格式化返回token和登录用户信息
	return serializer.Success(returnUser{
		Token: token,
		User:  serializer.BuildUser(user),
	})
}

postman调用示例

具体路由使用示例

代码语言:go
复制
v1 := r.Group("/api/v1")
	{
        // 不需要判断的接口放在外部
		v1.POST("user/login", api.UserLogin)
		v1.POST("user/register", api.UserRegiser)

		auth := v1.Group("")
		auth.Use(JWTAuth())
		{
			// 放入需要token 判断的接口
		}
	}

希望我的文章能够帮助到你!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 环境配置
  • 如何签发token?
    • 生成token
      • 解析token
      • Gin框架鉴权中间件实现
      • 该如何使用?
        • 登录接口示例
          • postman调用示例
            • 具体路由使用示例
            • 希望我的文章能够帮助到你!
            相关产品与服务
            消息队列 TDMQ
            消息队列 TDMQ (Tencent Distributed Message Queue)是腾讯基于 Apache Pulsar 自研的一个云原生消息中间件系列,其中包含兼容Pulsar、RabbitMQ、RocketMQ 等协议的消息队列子产品,得益于其底层计算与存储分离的架构,TDMQ 具备良好的弹性伸缩以及故障恢复能力。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档