Files

81 lines
2.3 KiB
Go
Raw Permalink Normal View History

2026-08-14 13:17:03 +08:00
// Package middleware 提供 Gin 中间件跨域、JWT 鉴权、超管校验
package middleware
import (
"strings"
"github.com/gin-gonic/gin"
"nl-game-api-gin/internal/database"
"nl-game-api-gin/internal/model"
"nl-game-api-gin/pkg/jwtutil"
"nl-game-api-gin/pkg/resp"
)
// CORS 跨域中间件:开发时前端(5173)与后端(8080)端口不同,需要放行跨域请求
func CORS() gin.HandlerFunc {
return func(c *gin.Context) {
origin := c.GetHeader("Origin")
if origin != "" {
c.Header("Access-Control-Allow-Origin", origin)
c.Header("Access-Control-Allow-Credentials", "true")
c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
c.Header("Access-Control-Allow-Headers", "Content-Type, Authorization")
}
// 预检请求直接返回 204
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(204)
return
}
c.Next()
}
}
// Auth JWT 鉴权中间件:从 Authorization: Bearer xxx 中解析用户身份
// 校验通过后将 user_id 与 role 写入上下文供后续处理函数使用
func Auth() gin.HandlerFunc {
return func(c *gin.Context) {
authHeader := c.GetHeader("Authorization")
token := strings.TrimPrefix(authHeader, "Bearer ")
if token == "" || token == authHeader {
resp.Unauthorized(c, "请先登录")
return
}
claims, err := jwtutil.Parse(token)
if err != nil {
resp.Unauthorized(c, "登录已过期,请重新登录")
return
}
// 查库校验账号仍然有效:否则封禁/删除的用户在 Token 过期前仍可操作全部接口
var user model.User
if err := database.DB.Select("status").First(&user, claims.UserID).Error; err != nil {
resp.Unauthorized(c, "账号不存在,请重新登录")
return
}
if user.Status == model.UserStatusBanned {
resp.Forbidden(c, "账号已被禁用")
return
}
// 身份信息写入请求上下文
c.Set("user_id", claims.UserID)
c.Set("role", claims.Role)
c.Next()
}
}
// AdminOnly 超管校验中间件:需在 Auth 之后使用,非超管直接拒绝
func AdminOnly() gin.HandlerFunc {
return func(c *gin.Context) {
if c.GetInt("role") != model.RoleAdmin {
resp.Forbidden(c, "仅超级管理员可操作")
return
}
c.Next()
}
}
// UID 从上下文取当前登录用户ID的快捷方法
func UID(c *gin.Context) int {
return c.GetInt("user_id")
}