Files
st/server/middleware/app_jwt.go

148 lines
3.5 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
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)))
}