93 lines
2.6 KiB
Go
93 lines
2.6 KiB
Go
package middleware
|
||
|
||
import (
|
||
"log"
|
||
"net/http"
|
||
|
||
"metazone.cc/metalab/internal/common"
|
||
"metazone.cc/metalab/internal/config"
|
||
"metazone.cc/metalab/internal/model"
|
||
"metazone.cc/metalab/internal/repository"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
)
|
||
|
||
// AdminAuth 管理后台页面认证中间件
|
||
// 逻辑同 AuthRequired(JWT 校验 + token_version 吊销检查)
|
||
// 但失败时重定向到首页,而非返回 JSON
|
||
// 成功时向 context 注入 uid/email/username/role
|
||
func AdminAuth(cfg *config.Config, userRepo *repository.UserRepo) gin.HandlerFunc {
|
||
return func(c *gin.Context) {
|
||
tokenStr, err := c.Cookie(common.CookieName)
|
||
if err != nil {
|
||
log.Printf("[AdminAuth] NO_COOKIE path=%s → 302", c.Request.URL.Path)
|
||
c.Redirect(http.StatusFound, "/")
|
||
c.Abort()
|
||
return
|
||
}
|
||
|
||
claims, err := parseToken(tokenStr, cfg.JWT.Secret)
|
||
if err != nil {
|
||
log.Printf("[AdminAuth] TOKEN_PARSE_FAIL path=%s err=%v → 302", c.Request.URL.Path, err)
|
||
common.ClearAuthCookies(c, cfg)
|
||
c.Redirect(http.StatusFound, "/")
|
||
c.Abort()
|
||
return
|
||
}
|
||
|
||
uid := uint(claims["uid"].(float64))
|
||
tokenVer := int(claims["ver"].(float64))
|
||
|
||
// 即时吊销检查
|
||
currentVer, err := userRepo.FindTokenVersion(uid)
|
||
if err != nil || tokenVer != currentVer {
|
||
if tokenVer != currentVer {
|
||
log.Printf("[AdminAuth] REVOKED: uid=%d tokenVer=%d dbVer=%d → 302", uid, tokenVer, currentVer)
|
||
} else {
|
||
log.Printf("[AdminAuth] DB_ERR: uid=%d err=%v → 302", uid, err)
|
||
}
|
||
common.ClearAuthCookies(c, cfg)
|
||
c.Redirect(http.StatusFound, "/")
|
||
c.Abort()
|
||
return
|
||
}
|
||
|
||
log.Printf("[AdminAuth] OK: uid=%d role=%v path=%s", uid, claims["role"], c.Request.URL.Path)
|
||
c.Set("uid", uid)
|
||
c.Set("email", claims["email"])
|
||
c.Set("username", claims["username"])
|
||
c.Set("role", claims["role"])
|
||
c.Next()
|
||
}
|
||
}
|
||
|
||
// RequireMinRole 角色权限检查(用于 API 路由)
|
||
// 不足时返回 JSON 403
|
||
func RequireMinRole(minRole string) gin.HandlerFunc {
|
||
return func(c *gin.Context) {
|
||
role, exists := c.Get("role")
|
||
if !exists || !model.HasMinRole(role.(string), minRole) {
|
||
c.AbortWithStatusJSON(http.StatusForbidden, gin.H{
|
||
"success": false, "message": "权限不足",
|
||
})
|
||
return
|
||
}
|
||
c.Next()
|
||
}
|
||
}
|
||
|
||
// RequirePageRole 角色权限检查(用于 SSR 页面路由)
|
||
// 不足时 302 跳转首页
|
||
func RequirePageRole(minRole string) gin.HandlerFunc {
|
||
return func(c *gin.Context) {
|
||
role, exists := c.Get("role")
|
||
if !exists || !model.HasMinRole(role.(string), minRole) {
|
||
log.Printf("[RequirePageRole] DENY: role=%v need=%s path=%s → 302", role, minRole, c.Request.URL.Path)
|
||
c.Redirect(http.StatusFound, "/")
|
||
c.Abort()
|
||
return
|
||
}
|
||
c.Next()
|
||
}
|
||
}
|