148 lines
3.5 KiB
Go
148 lines
3.5 KiB
Go
package middleware
|
||
|
||
import (
|
||
"errors"
|
||
"strconv"
|
||
|
||
"git.echol.cn/loser/st/server/global"
|
||
"git.echol.cn/loser/st/server/model/app"
|
||
"git.echol.cn/loser/st/server/model/common/response"
|
||
"git.echol.cn/loser/st/server/utils"
|
||
"github.com/gin-gonic/gin"
|
||
"github.com/golang-jwt/jwt/v5"
|
||
)
|
||
|
||
// AppJWTAuth 前台用户 JWT 认证中间件
|
||
func AppJWTAuth() gin.HandlerFunc {
|
||
return func(c *gin.Context) {
|
||
token := GetToken(c)
|
||
if token == "" {
|
||
response.FailWithDetailed(gin.H{"reload": true}, "未登录或非法访问", c)
|
||
c.Abort()
|
||
return
|
||
}
|
||
|
||
// 解析 JWT
|
||
claims, err := utils.ParseAppToken(token)
|
||
if err != nil {
|
||
if errors.Is(err, jwt.ErrTokenExpired) {
|
||
response.FailWithDetailed(gin.H{"reload": true}, "Token 已过期", c)
|
||
} else {
|
||
response.FailWithDetailed(gin.H{"reload": true}, "Token 无效", c)
|
||
}
|
||
c.Abort()
|
||
return
|
||
}
|
||
|
||
// 验证用户类型(确保是前台用户)
|
||
if claims.UserType != utils.UserTypeApp {
|
||
response.FailWithMessage("无效的用户类型", c)
|
||
c.Abort()
|
||
return
|
||
}
|
||
|
||
// 查询用户是否存在
|
||
var user app.AppUser
|
||
err = global.GVA_DB.Where("id = ?", claims.UserID).First(&user).Error
|
||
if err != nil {
|
||
response.FailWithMessage("用户不存在", c)
|
||
c.Abort()
|
||
return
|
||
}
|
||
|
||
// 检查用户状态
|
||
if !user.Enable {
|
||
response.FailWithMessage("用户已被禁用", c)
|
||
c.Abort()
|
||
return
|
||
}
|
||
|
||
if user.Status != "active" {
|
||
response.FailWithMessage("账户状态异常", c)
|
||
c.Abort()
|
||
return
|
||
}
|
||
|
||
// 将用户信息存入上下文
|
||
c.Set("appUserId", user.ID)
|
||
c.Set("appUser", &user)
|
||
c.Set("appUsername", user.Username)
|
||
|
||
c.Next()
|
||
}
|
||
}
|
||
|
||
// GetAppUserID 从上下文获取前台用户 ID(需要鉴权的接口使用)
|
||
func GetAppUserID(c *gin.Context) uint {
|
||
if userID, exists := c.Get("appUserId"); exists {
|
||
return userID.(uint)
|
||
}
|
||
return 0
|
||
}
|
||
|
||
// GetOptionalAppUserID 从上下文获取可选的前台用户 ID(公开接口使用)
|
||
// 如果用户已登录,返回用户 ID;否则返回 nil
|
||
func GetOptionalAppUserID(c *gin.Context) *uint {
|
||
// 先尝试从上下文获取(通过鉴权中间件设置)
|
||
if userID, exists := c.Get("appUserId"); exists {
|
||
if id, ok := userID.(uint); ok {
|
||
return &id
|
||
}
|
||
}
|
||
|
||
// 如果上下文中没有,尝试手动解析 Token(用于公开接口)
|
||
token := GetToken(c)
|
||
if token == "" {
|
||
return nil
|
||
}
|
||
|
||
claims, err := utils.ParseAppToken(token)
|
||
if err != nil {
|
||
return nil
|
||
}
|
||
|
||
if claims.UserType != utils.UserTypeApp {
|
||
return nil
|
||
}
|
||
|
||
return &claims.UserID
|
||
}
|
||
|
||
// GetAppUser 从上下文获取前台用户信息
|
||
func GetAppUser(c *gin.Context) *app.AppUser {
|
||
if user, exists := c.Get("appUser"); exists {
|
||
return user.(*app.AppUser)
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// GetAppUsername 从上下文获取前台用户名
|
||
func GetAppUsername(c *gin.Context) string {
|
||
if username, exists := c.Get("appUsername"); exists {
|
||
return username.(string)
|
||
}
|
||
return ""
|
||
}
|
||
|
||
// GetToken 从请求中获取 Token
|
||
// 优先从 Header 获取,其次从 Query 参数获取
|
||
func GetToken(c *gin.Context) string {
|
||
token := c.Request.Header.Get("x-token")
|
||
if token == "" {
|
||
token = c.Request.Header.Get("Authorization")
|
||
if token != "" && len(token) > 7 && token[:7] == "Bearer " {
|
||
token = token[7:]
|
||
}
|
||
}
|
||
if token == "" {
|
||
token = c.Query("token")
|
||
}
|
||
return token
|
||
}
|
||
|
||
// SetAppUserID 设置用户 ID 到上下文(用于某些特殊场景)
|
||
func SetAppUserID(c *gin.Context, userID uint) {
|
||
c.Set("appUserId", userID)
|
||
c.Set("appUserIdStr", strconv.Itoa(int(userID)))
|
||
}
|