Files
nl-im-service/internal/middleware/auth.go
2025-12-15 21:57:21 +08:00

117 lines
3.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* package middleware
* 作用JWT认证中间件
*/
package middleware
import (
"log"
"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
}
// 调试日志打印解析出的用户ID帮助排查JWT问题
log.Printf("🔑 [JWT] 请求: %s %s | 解析出的用户ID: %s", c.Request.Method, c.Request.URL.Path, userID)
// 步骤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()
}
}