初始化项目:基础设施 + 用户认证 + 后台管理系统 + AGPL 3.0 许可

This commit is contained in:
2026-05-26 13:46:33 +08:00
parent 1315df6501
commit 483fdd919f
56 changed files with 5804 additions and 40 deletions

View File

@ -0,0 +1,92 @@
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 管理后台页面认证中间件
// 逻辑同 AuthRequiredJWT 校验 + 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()
}
}