Files
nl-im-service/internal/middleware/auth.go

113 lines
3.1 KiB
Go
Raw Normal View History

2025-12-03 11:00:47 +08:00
/**
* package middleware
* 作用JWT认证中间件
*/
package middleware
import (
"net/http"
"xk-websocket-v2/internal/utils"
"github.com/gin-gonic/gin"
)
/**
* JWTAuthMiddleware
*
* 功能JWT认证中间件
*
* 作用
* 1. 从HTTP请求头或查询参数中提取JWT Token
* 2. 验证Token的有效性和过期时间
* 3. 从Token中解析出用户ID
* 4. 将用户ID注入到Gin Context中供后续处理器使用
* 5. 如果Token无效或缺失返回401未授权错误
*
* 使用场景
* - 需要用户登录才能访问的API接口
* - 需要在处理器中获取当前用户信息的接口
*
* @returns gin.HandlerFunc 中间件处理函数
*/
func JWTAuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
// 步骤1: 从HTTP请求头中获取Token标准方式
token := c.GetHeader("Authorization")
if token == "" {
// 步骤2: 如果请求头中没有,尝试从查询参数获取(兼容旧代码)
token = c.Query("token")
}
// 步骤3: 如果仍然没有Token返回401未授权错误
if token == "" {
c.JSON(http.StatusUnauthorized, gin.H{"error": "缺少认证Token"})
c.Abort() // 终止请求处理
return
}
// 步骤4: 移除 "Bearer " 前缀(如果存在)
// 标准JWT Token格式Bearer <token>
if len(token) > 7 && token[:7] == "Bearer " {
token = token[7:]
}
// 步骤5: 验证Token的有效性和过期时间
userID, err := utils.ValidateToken(token)
if err != nil {
// Token无效或已过期返回401错误
c.JSON(http.StatusUnauthorized, gin.H{"error": "Token无效或已过期: " + err.Error()})
c.Abort()
return
}
// 步骤6: 将解析出的用户ID注入到Context中
// 后续处理器可以通过 c.Get("user_id") 获取当前用户ID
c.Set("user_id", userID)
c.Next() // 继续执行下一个中间件或处理器
}
}
/**
* OptionalJWTAuthMiddleware
*
* 功能可选的JWT认证中间件不强制要求认证
*
* 作用
* 1. 如果请求中提供了Token则验证Token并注入用户ID
* 2. 如果没有提供Token则继续执行不返回错误
* 3. 适用于既支持登录用户访问也支持匿名用户访问的接口
*
* 使用场景
* - 公开接口但登录用户可以获取更多信息
* - 兼容旧代码不强制要求认证
*
* @returns gin.HandlerFunc 中间件处理函数
*/
func OptionalJWTAuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
// 步骤1: 尝试从请求头或查询参数获取Token
token := c.GetHeader("Authorization")
if token == "" {
token = c.Query("token")
}
// 步骤2: 如果提供了Token则验证并注入用户ID
if token != "" {
// 移除 "Bearer " 前缀
if len(token) > 7 && token[:7] == "Bearer " {
token = token[7:]
}
// 验证Token如果有效则注入用户ID
// 如果Token无效不返回错误继续执行允许匿名访问
if userID, err := utils.ValidateToken(token); err == nil {
c.Set("user_id", userID)
}
}
// 步骤3: 继续执行无论是否有Token
c.Next()
}
}