【gin】中间件使用之jwt身份认证和Cors跨域,go案例

Gin-3 中间件编程及 JWT 身份认证

1. Gin 中间件概述

中间件是处理 HTTP 请求的函数,可以在请求到达路由处理函数之前或之后对请求进行处理。

在 Gin 框架中,中间件常用于处理日志记录、身份验证、权限控制等功能。

go 复制代码
router := gin.Default()
router.Use(middleware) // 使用中间件

中间件可以通过 Use 方法进行添加,并且可以用于所有路由特定路由组

2. JWT 简介

https://github.com/golang-jwt/jwt

JSON Web Token(JWT)是一种用于认证和授权的标准。JWT 包含三个部分:

  1. 头部 (Header)
  2. 载荷 (Payload)
  3. 签名 (Signature)
text 复制代码
JWT = Base64UrlEncode(HEADER) + "." + Base64UrlEncode(PAYLOAD) + "." + Base64UrlEncode(SIGNATURE)

JWT 的优点是自包含,它在用户和服务之间传递信息时不依赖于存储。

由于 JWT 包含所有必要的用户信息,服务端不需要保持用户的状态。

3. Gin 中的 JWT 身份认证实现

在 Gin 中实现 JWT 身份认证主要包含以下步骤:

  1. 生成 JWT Token:登录时生成 JWT Token。
  2. 验证 JWT Token:通过中间件验证请求中的 Token。
  3. 访问受保护路由:只有验证通过的用户才能访问受保护的路由。

3.1 JWT 生成与验证函数

通过以下代码,您可以生成和验证 JWT Token:

go 复制代码
package jwt_plugin

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

var key = "abcdefg123" // 用于加密和解密的密钥

// 数据结构,存储用户信息和标准声明
type Data struct {
    Name   string `json:"name"`
    Age    int    `json:"age"`
    Gender int    `json:"gender"`
    jwt.RegisteredClaims
}

// 生成 JWT Token
func Sign(data jwt.Claims) (string, error) {
    token := jwt.NewWithClaims(jwt.SigningMethodHS256, data)
    sign, err := token.SignedString([]byte(key))
    if err != nil {
        return "", err
    }
    return sign, nil
}

// 验证 JWT Token
func Verify(sign string, data jwt.Claims) error {
    _, err := jwt.ParseWithClaims(sign, data, func(token *jwt.Token) (any, error) {
        return []byte(key), nil
    })
    return err
}

生成 JWT Token 时,我们会使用 Sign 函数,验证时使用 Verify 函数。
Sign 函数会将用户信息(载荷)和签名一起返回,Verify 函数用于验证 JWT Token 是否有效。

3.2 登录接口实现

用户登录时,通过 Login 函数生成 JWT Token,并返回给客户端。

go 复制代码
package login

import (
    "github.com/gin-gonic/gin"
    "golang13-gin/jwt_plugin"
    "net/http"
    "time"
)

func Login(c *gin.Context) {
    // 用户信息及 JWT 载荷
    data := jwt_plugin.Data{
        Name:   "nick",
        Age:    18,
        Gender: 1,
        RegisteredClaims: jwt.RegisteredClaims{
            ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour)),
            IssuedAt:  jwt.NewNumericDate(time.Now()),
            NotBefore: jwt.NewNumericDate(time.Now()),
        },
    }
    
    // 生成 JWT Token
    sign, err := jwt_plugin.Sign(data)
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{
            "error": err.Error(),
        })
        return
    }

    // 返回 JWT Token
    c.JSON(http.StatusOK, gin.H{
        "access_token": sign,
    })
}

登录成功后,系统会返回一个包含用户信息和有效期的 JWT Token。

3.3 JWT 身份验证中间件

go 复制代码
package middleware

import (
    "github.com/gin-gonic/gin"
    "golang13-gin/jwt_plugin"
    "net/http"
)

func Auth() gin.HandlerFunc {
    return func(c *gin.Context) {
        accessToken := c.Request.Header.Get("access_token") // 获取请求头中的 Token
        data := &jwt_plugin.Data{}
        err := jwt_plugin.Verify(accessToken, data) // 验证 Token
        if err != nil {
            c.JSON(http.StatusForbidden, gin.H{
                "error": "身份认证失败",
            })
            c.Abort() // 中止请求
        }
        c.Set("auth_info", data) // 将用户信息存储在上下文中
        c.Next() // 继续后续处理
    }
}

身份验证中间件 Auth 会从请求头中提取 JWT Token 并进行验证。如果验证失败,返回 403 错误;否则将用户信息存储到上下文,供后续路由使用。

4. CORS 中间件

CORS(跨域资源共享)允许服务器指定哪些源(Origin)可以访问资源。以下是设置 CORS 中间件的代码:

go 复制代码
package middleware

import (
    "github.com/gin-contrib/cors"
    "github.com/gin-gonic/gin"
)

func Cors() gin.HandlerFunc {
    return cors.New(cors.Config{
        AllowAllOrigins: true,
        AllowHeaders: []string{
            "Origin", "Content-Length", "Content-Type",
        },
        AllowMethods: []string{
            "GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS",
        },
    })
}

CORS 中间件配置允许来自任何来源的请求,并且可以处理指定的 HTTP 方法和头部。

5. 路由初始化与中间件使用

在 Gin 中,可以通过 Use 方法将中间件添加到路由组中,以下是一个例子:

go 复制代码
func InitRoutes(r *gin.Engine) {   
    api := r.Group("/api")   
    api.Use(middleware.Cors(), middleware.Auth()) // 使用 CORS 和 JWT 验证中间件



    InitCourse(api)   
    InitUser(api)   
    InitUpload(api)   

    notAuthApi := r.Group("/api")   
    notAuthApi.Use(middleware.Cors())   
    InitLogin(notAuthApi) // 不需要身份验证的路由   
}

总结

概念 描述 代码示例
Gin 中间件 中间件是一个函数,用来处理 HTTP 请求。在请求进入路由处理函数之前或之后,执行某些操作。 router.Use(middleware)
JWT (JSON Web Token) 一种用于认证和授权的标准格式,通过三个部分组成:头部、载荷和签名。它具有自包含特性,可以在分布式系统中使用。 token := jwt.NewWithClaims(jwt.SigningMethodHS256, data)
JWT 生成 通过载荷和密钥生成 JWT Token。 sign, err := jwt_plugin.Sign(data)
JWT 验证 通过 Token 验证用户身份,确保请求的合法性。 err := jwt_plugin.Verify(accessToken, data)
身份认证中间件 在请求到达目标路由之前,验证请求中的 JWT Token,确保只有通过验证的请求才能继续处理。 func Auth() gin.HandlerFunc { return func(c *gin.Context) { ... } }
CORS 中间件 解决浏览器跨域问题,允许不同域的请求访问服务器资源。 func Cors() gin.HandlerFunc { return cors.New(cors.Config{ AllowAllOrigins: true }) }
路由组 将具有共同前缀的路由放在一个组中,方便统一管理和中间件的应用。 api := r.Group("/api")
JWT 载荷 JWT 中的数据部分,包含用户信息和其他元数据。可以自定义内容,也可以使用预定义的注册声明(如过期时间)。 RegisteredClaims: jwt.RegisteredClaims{ ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour)) }
路由配置 定义与中间件、请求处理函数相关的路由。 InitLogin(notAuthApi)

表格解释:

  1. Gin 中间件 是一类用于在路由处理函数执行前或后处理请求的函数,常见的中间件包括身份认证、中间件控制等。
  2. JWT 是一种 JSON 格式的认证方式,包含头部、载荷和签名,适用于分布式系统,解决了服务端无状态的问题。
  3. JWT 生成和验证 是通过特定的密钥和载荷数据生成的,可以通过库函数轻松实现生成和验证操作。
  4. 身份认证中间件 通过在请求处理中拦截请求并验证 JWT Token 是否有效来确保用户身份的合法性。
  5. CORS 中间件 允许不同来源的客户端发起请求,解决跨域问题,常见于前后端分离的应用场景。
  6. 路由组 可以帮助组织和管理具有共同特征的路由,通过给路由组添加中间件,使得多个路由共享特定的功能。
  7. JWT 载荷 中的数据部分,存储的是用户信息以及与身份认证相关的信息(如过期时间等)。

JWT载荷

JWT 载荷部分是什么,是否可有可无?

JWT 的载荷部分是存储在 Token 中的实际信息,它包含了 声明(claims),这些声明通常用于存储用户信息、权限、Token 的有效期等。

JWT 载荷部分包含以下几种类型的声明:

  • 注册声明(Registered Claims):如 exp(过期时间)、iat(签发时间)、sub(主题)等。
  • 公共声明(Public Claims):可以自定义,用于表示用户信息或其他数据。
  • 私有声明(Private Claims):由双方约定用于传递的信息。
    是否可有可无?

如果只是需要传递一个简单的标识符(如用户 ID),那么可以简化载荷部分。

但通常,JWT 的载荷是不可或缺的,因为它包含了 Token 的有效期、权限等重要信息。

如果载荷部分为空或缺少必要的字段,Token 的使用价值将大大降低。


https://github.com/0voice

相关推荐
寻找09之夏14 小时前
【Go】:深入解析 Go 1.24:新特性、改进与最佳实践
开发语言·后端·golang·go1.24
{⌐■_■}17 小时前
【gin】模型绑定、参数验证及文件上传go案例演示
android·golang·gin
Ai 编码助手18 小时前
Go语言的数据竞争 (Data Race) 和 竞态条件 (Race Condition)
开发语言·后端·golang
joesx18 小时前
GORM(Go语言数据交互库)
数据库·golang
Code花园20 小时前
Bash语言的多线程编程
开发语言·后端·golang
飞的肖1 天前
使用中间件自动化部署java应用
java·中间件·自动化
编程小筑1 天前
R语言的数据库编程
开发语言·后端·golang
风向决定发型丶1 天前
GO语言实现KMP算法
算法·golang
大熊程序猿1 天前
golang 环境变量配置
开发语言·后端·golang