首页 > 其他分享 >Gin框架下的JWT

Gin框架下的JWT

时间:2024-06-06 22:22:27浏览次数:20  
标签:return 框架 jwt JWT token gin Gin userID

Gin框架下的JWT

什么是JWT

我们都知道,HTTP协议是无状态的,click here,那么服务端怎么知道用户状态的呢(比如是否登录呢),这里就需要用到中间件来进行用户认证。

中间件认证有这么几种方式

  • session

  • token

    token和session最大的区别就是token是存储在客户端的:
    我们都知道,session是存储在服务端的,每次请求到来的时候,通过cookie携带的sessionID与服务器内部存储的在线session进行比对,如果有该sessionID,就说明该用户已登录,但是这样就暴露出session最大的确定,服务端压力过大,同时如果是服务器是一个集群,在负载均衡后很可能处理该请求的服务器并不是存储该请求session的服务器。所以为了解决这些问题,token便产生了。

token和session类似,单不存储在服务端,当用户请求连接时,服务端分发一个token表示该用户的“令牌”,每次用户发器请求都携带这个令牌在请求头中(为保证安全性大部分存储在请求头中),和session一样,客户端只转发,不处理token,客户端收到带有token打请求后解析token,解析出的信息就可以唯一标识某个用户(例如预设的UID)。

JWT,读作:jot ,表示:JSON Web Tokens

JWT 标准的 Token 由三个部分组成:header.payload.signature

header(头部)
payload(数据)
signature(签名)

中间用点分隔开,并且都会使用 Base64 编码,所以真正的 Token 看起来像这样:
eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJuaW5naGFvLm5ldCIsImV4cCI6IjE0Mzg5NTU0NDUiLCJuYW1lIjoid2FuZ2hhbyIsImFkbWluIjp0cnVlfQ.SwyHTEx_RQppr97g4J5lKXtabJecpejuef8AqKYMAJc

每个 JWT token 里面都有一个 header,也就是头部数据。里面包含了使用的算法,这个 JWT 是不是带签名的或者加密的。主要就是说明一下怎么处理这个 JWT token 。

唯一在头部里面要包含的是 alg 这个属性,如果是加密的 JWT,这个属性的值就是使用的签名或者解密用的算法。如果是未加密的 JWT,这个属性的值要设置成 none。

Payload

Payload 里面是 Token 的具体内容,这些内容里面有一些是标准字段,你也可以添加其它需要的内容。
例如:UID , timeLogin , Ifadmin等等

Signature

JWT 的最后一部分是 Signature ,这部分内容有三个部分——

  • 第一部分 :Base64 编码的header。
  • 第二部分:Base64 编码的payload。
  • 第三部分:再用加密算法加密一下,加密的时候要放进去一个 Secret ,这个相当于是一个密码,这个密码秘密地存储在服务端,不得泄露。

处理过程可以理解为

const encodedString = base64UrlEncode(header) + "." + base64UrlEncode(payload); 
HMACSHA256(encodedString, 'secret');

基于gin框架的JWT

废话不多说,直接上代码,原理上面讲过,详情请见注释!

package main

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

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

var mySecret = []byte("haomiao000") // 直接将密钥作为字符串存储(这里只是个例子,通常会非常复杂保证安全性)

// 定义自定义声明结构体并内嵌 jwt.RegisteredClaims
type MyClaims struct {
	UserID int64 `json:"user_id"`
	jwt.RegisteredClaims
}

// 生成JWT
func GenToken(userID int64) (string, error) {
	// 创建自定义声明
	claims := MyClaims{
		UserID: userID,
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(1 * time.Hour)), // 过期时间设置为1小时
			Issuer:    "jwt",                                             // 签发人
		},
	}
	// 使用指定的签名方法创建签名对象
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	// 使用指定的secret签名并获得完整的编码后的字符串token
	return token.SignedString(mySecret)
}

// 解析JWT
func ParseToken(tokenString string) (*MyClaims, error) {
	var claims MyClaims
	// 解析token
	token, err := jwt.ParseWithClaims(tokenString, &claims, keyFunc)
	if err != nil {
		return nil, fmt.Errorf("parsing token: %w", err)
	}
	// 校验token
	if !token.Valid {
		return nil, errors.New("invalid token")
	}
	return &claims, nil
}

// keyFunc 定义获取密钥的函数
func keyFunc(_ *jwt.Token) (interface{}, error) {
	return mySecret, nil
}

func main() {
	// 初始化Gin引擎
	r := gin.Default()

	// 设置路由
	r.POST("/login", loginHandler)
	authGroup := r.Group("/api")
	authGroup.Use(authMiddleware())
	authGroup.GET("/user", getUserHandler)

	// 启动服务器
	r.Run(":8080")
}

// authMiddleware 定义JWT身份验证中间件
func authMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		tokenString := c.GetHeader("Authorization")
		if tokenString == "" {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
			c.Abort()
			return
		}

		claims, err := ParseToken(tokenString)
		if err != nil {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
			c.Abort()
			return
		}

		// 在上下文中设置用户ID
		c.Set("userID", claims.UserID)

		// 继续处理请求
		c.Next()
	}
}

// loginHandler 登录处理程序
func loginHandler(c *gin.Context) {
	// 这里可以编写身份验证逻辑
	// 例如从请求中获取用户名和密码,然后验证用户信息

	// 假设身份验证成功后,获取用户ID
	userID := int64(123)

	// 生成JWT
	token, err := GenToken(userID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Internal Server Error"})
		return
	}

	// 返回JWT给客户端
	c.JSON(http.StatusOK, gin.H{"token": token})
}

// getUserHandler 示例处理程序,需要JWT验证
func getUserHandler(c *gin.Context) {
	userID, exists := c.Get("userID")
	if !exists {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Internal Server Error"})
		return
	}

	// 在这里可以使用userID进行进一步的处理,例如从数据库中检索用户信息等

	c.JSON(http.StatusOK, gin.H{"userID": userID})
}
  • 登录生成token

  • 验证token

标签:return,框架,jwt,JWT,token,gin,Gin,userID
From: https://www.cnblogs.com/atongmuhao/p/18236172

相关文章

  • 有关于JavaSSM项目的前期框架准备
    一、项目准备的工具及框架使用工具:idea创建工程:maven工程使用框架:ssm(spring+springmvc+mybatis)服务器:tomcat二、项目前期内容1、pom.xml导入所依赖的jar包(这里附上代码)<dependencies><!--扫入spring相关依赖--><dependency><group......
  • Atcoder Beginner Contest 355
    A-WhoAtetheCake?#include<bits/stdc++.h>usingnamespacestd;usingi64=longlong;intmain(){ ios::sync_with_stdio(false),cin.tie(nullptr); intA,B; cin>>A>>B; if(A==B)cout<<-1; elsecout<<6-A......
  • 插件:vite-plugin-electron
    源文档地址:vite-plugin-electron安装npmi-Dvite-plugin-electron将vite-plugin-electron添加到vite.config.ts的插件部分importelectronfrom'vite-plugin-electron/simple'exportdefault{plugins:[electron({main:{//`build.lib.ent......
  • 从零手写实现 nginx-07-大文件传输 分块传输(chunked transfer)/ 分页传输(paging)
    前言大家好,我是老马。很高兴遇到你。我们希望实现最简单的http服务信息,可以处理静态文件。如果你想知道servlet如何处理的,可以参考我的另一个项目:手写从零实现简易版tomcatminicat手写nginx系列如果你对nginx原理感兴趣,可以阅读:从零手写实现nginx-01-为什么不......
  • nginx mirror流量镜像详细介绍以及实战示例
    nginxmirror流量镜像详细介绍以及实战示例1.nginxmirror作用2.nginx安装3.修改配置3.1.nginx.conf3.2.conf.d目录下添加default.conf配置文件3.3.nginx配置注意事项3.3.nginx重启4.测试1.nginxmirror作用为了便于排查问题,可能希望线上的请求能够同步到测试环境,以......
  • AI框架之Spring AI与Spring Cloud Alibaba AI使用讲解
    目录1AI框架1.1SpringAI简介1.2SpringAI使用1.2.1pom.xml1.2.2可实现的功能1.3SpringCloudAlibabaAI1.4SpringCloudAlibabaAI实践操作1.4.1pom.xml1.4.2配置文件1.4.3对接文本模型1.4.4文生图模型1.4.5语音合成模型1AI框架1.1SpringAI简介在软件开......
  • Master ABP Framework(熟练掌握 ABP 框架)
    前言ABP框架是一个完整的基础框架,用于通过遵循软件开发的最佳实践和惯例来创建现代Web应用程序。ABP提供了一个高级框架和生态系统,以帮助您实施“不要重复自己”(DRY)原则并专注于您的业务代码。本书由ABP框架的创建者撰写,将帮助您从头开始全面了解ABP框架和现代Web应用程序开发......
  • 锐捷校园网自助服务系统 login_judge.jsf 任意文件读取漏洞复现(XVE-2024-2116)
    0x01产品简介锐捷校园网自助服务系统是锐捷网络推出的一款面向学校和校园网络管理的解决方案。该系统旨在提供便捷的网络自助服务,使学生、教职员工和网络管理员能够更好地管理和利用校园网络资源。0x02漏洞概述校园网自助服务系统/selfservice/selfservice/module/scgroup......
  • 编译安装Nginx
    一、Linux常见的IO模型I/O在计算机中指Input/Output,IOPS(Input/OutputPerSecond)即每秒的输入输出量(或读写次数),是衡量磁盘性能的主要指标之一。IOPS是指单位时间内系统能处理的I/O请求数量,一般以每秒处理的I/O请求数量为单位,I/O请求通常为读或写数据操作请求。一次完整的......
  • nginx 多个域名使用同一个通配符证书,并使用 include 指令来避免在多个 server 块中重
    1.创建SSL配置文件首先,创建一个包含SSL配置的文件,例如ssl_params.conf:#ssl_params.confssl_certificate/path/to/your/wildcard_certificate.pem;ssl_certificate_key/path/to/your/wildcard_private_key.key;ssl_session_timeout5m;ssl_ciphersECDHE-......