This commit is contained in:
xujiang
2025-07-10 18:09:11 +08:00
parent 5cbdc5af73
commit 604b9e59ba
95 changed files with 23709 additions and 19 deletions

View File

@ -0,0 +1,217 @@
package middleware
import (
"net/http"
"strings"
"github.com/gin-gonic/gin"
"photography-backend/internal/service/auth"
"photography-backend/internal/model/entity"
)
// AuthMiddleware 认证中间件
type AuthMiddleware struct {
jwtService *auth.JWTService
}
// NewAuthMiddleware 创建认证中间件
func NewAuthMiddleware(jwtService *auth.JWTService) *AuthMiddleware {
return &AuthMiddleware{
jwtService: jwtService,
}
}
// RequireAuth 需要认证的中间件
func (m *AuthMiddleware) RequireAuth() gin.HandlerFunc {
return func(c *gin.Context) {
// 从Header中获取Authorization
authHeader := c.GetHeader("Authorization")
if authHeader == "" {
c.JSON(http.StatusUnauthorized, gin.H{
"error": "Authorization header is required",
})
c.Abort()
return
}
// 检查Bearer前缀
if !strings.HasPrefix(authHeader, "Bearer ") {
c.JSON(http.StatusUnauthorized, gin.H{
"error": "Invalid authorization header format",
})
c.Abort()
return
}
// 提取token
token := strings.TrimPrefix(authHeader, "Bearer ")
// 验证token
claims, err := m.jwtService.ValidateToken(token)
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{
"error": "Invalid or expired token",
})
c.Abort()
return
}
// 将用户信息存入上下文
c.Set("user_id", claims.UserID)
c.Set("username", claims.Username)
c.Set("user_role", claims.Role)
c.Next()
}
}
// RequireRole 需要特定角色的中间件
func (m *AuthMiddleware) RequireRole(requiredRole string) gin.HandlerFunc {
return func(c *gin.Context) {
userRole, exists := c.Get("user_role")
if !exists {
c.JSON(http.StatusUnauthorized, gin.H{
"error": "User role not found in context",
})
c.Abort()
return
}
roleStr, ok := userRole.(string)
if !ok {
c.JSON(http.StatusUnauthorized, gin.H{
"error": "Invalid user role",
})
c.Abort()
return
}
// 检查角色权限
if !m.hasPermission(roleStr, requiredRole) {
c.JSON(http.StatusForbidden, gin.H{
"error": "Insufficient permissions",
})
c.Abort()
return
}
c.Next()
}
}
// RequireAdmin 需要管理员权限的中间件
func (m *AuthMiddleware) RequireAdmin() gin.HandlerFunc {
return m.RequireRole(string(entity.UserRoleAdmin))
}
// RequirePhotographer 需要摄影师权限的中间件
func (m *AuthMiddleware) RequirePhotographer() gin.HandlerFunc {
return m.RequireRole(string(entity.UserRolePhotographer))
}
// OptionalAuth 可选认证中间件
func (m *AuthMiddleware) OptionalAuth() gin.HandlerFunc {
return func(c *gin.Context) {
authHeader := c.GetHeader("Authorization")
if authHeader == "" {
c.Next()
return
}
if !strings.HasPrefix(authHeader, "Bearer ") {
c.Next()
return
}
token := strings.TrimPrefix(authHeader, "Bearer ")
claims, err := m.jwtService.ValidateToken(token)
if err != nil {
c.Next()
return
}
// 将用户信息存入上下文
c.Set("user_id", claims.UserID)
c.Set("username", claims.Username)
c.Set("user_role", claims.Role)
c.Next()
}
}
// GetCurrentUser 获取当前用户ID
func GetCurrentUser(c *gin.Context) (uint, bool) {
userID, exists := c.Get("user_id")
if !exists {
return 0, false
}
id, ok := userID.(uint)
return id, ok
}
// GetCurrentUserRole 获取当前用户角色
func GetCurrentUserRole(c *gin.Context) (string, bool) {
userRole, exists := c.Get("user_role")
if !exists {
return "", false
}
role, ok := userRole.(string)
return role, ok
}
// GetCurrentUsername 获取当前用户名
func GetCurrentUsername(c *gin.Context) (string, bool) {
username, exists := c.Get("username")
if !exists {
return "", false
}
name, ok := username.(string)
return name, ok
}
// IsAuthenticated 检查是否已认证
func IsAuthenticated(c *gin.Context) bool {
_, exists := c.Get("user_id")
return exists
}
// IsAdmin 检查是否为管理员
func IsAdmin(c *gin.Context) bool {
role, exists := GetCurrentUserRole(c)
if !exists {
return false
}
return role == string(entity.UserRoleAdmin)
}
// IsPhotographer 检查是否为摄影师或以上
func IsPhotographer(c *gin.Context) bool {
role, exists := GetCurrentUserRole(c)
if !exists {
return false
}
return role == string(entity.UserRolePhotographer) || role == string(entity.UserRoleAdmin)
}
// hasPermission 检查权限
func (m *AuthMiddleware) hasPermission(userRole, requiredRole string) bool {
roleLevel := map[string]int{
string(entity.UserRoleUser): 1,
string(entity.UserRolePhotographer): 2,
string(entity.UserRoleAdmin): 3,
}
userLevel, exists := roleLevel[userRole]
if !exists {
return false
}
requiredLevel, exists := roleLevel[requiredRole]
if !exists {
return false
}
return userLevel >= requiredLevel
}

View File

@ -0,0 +1,58 @@
package middleware
import (
"net/http"
"github.com/gin-gonic/gin"
"photography-backend/internal/config"
)
// CORSMiddleware CORS中间件
func CORSMiddleware(cfg *config.CORSConfig) gin.HandlerFunc {
return func(c *gin.Context) {
origin := c.GetHeader("Origin")
// 检查是否允许的来源
allowed := false
for _, allowedOrigin := range cfg.AllowedOrigins {
if allowedOrigin == "*" || allowedOrigin == origin {
allowed = true
break
}
}
if allowed {
c.Header("Access-Control-Allow-Origin", origin)
}
// 设置其他CORS头
c.Header("Access-Control-Allow-Methods", joinStrings(cfg.AllowedMethods, ", "))
c.Header("Access-Control-Allow-Headers", joinStrings(cfg.AllowedHeaders, ", "))
c.Header("Access-Control-Max-Age", "86400")
if cfg.AllowCredentials {
c.Header("Access-Control-Allow-Credentials", "true")
}
// 处理预检请求
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(http.StatusNoContent)
return
}
c.Next()
}
}
// joinStrings 连接字符串数组
func joinStrings(strs []string, sep string) string {
if len(strs) == 0 {
return ""
}
result := strs[0]
for i := 1; i < len(strs); i++ {
result += sep + strs[i]
}
return result
}

View File

@ -0,0 +1,74 @@
package middleware
import (
"time"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
// LoggerMiddleware 日志中间件
func LoggerMiddleware(logger *zap.Logger) gin.HandlerFunc {
return func(c *gin.Context) {
start := time.Now()
path := c.Request.URL.Path
raw := c.Request.URL.RawQuery
// 处理请求
c.Next()
// 计算延迟
latency := time.Since(start)
// 获取请求信息
clientIP := c.ClientIP()
method := c.Request.Method
statusCode := c.Writer.Status()
bodySize := c.Writer.Size()
if raw != "" {
path = path + "?" + raw
}
// 记录日志
logger.Info("HTTP Request",
zap.String("method", method),
zap.String("path", path),
zap.String("client_ip", clientIP),
zap.Int("status_code", statusCode),
zap.Int("body_size", bodySize),
zap.Duration("latency", latency),
zap.String("user_agent", c.Request.UserAgent()),
)
}
}
// RequestIDMiddleware 请求ID中间件
func RequestIDMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
requestID := c.GetHeader("X-Request-ID")
if requestID == "" {
requestID = generateRequestID()
}
c.Set("request_id", requestID)
c.Header("X-Request-ID", requestID)
c.Next()
}
}
// generateRequestID 生成请求ID
func generateRequestID() string {
// 简单实现实际应用中可能需要更复杂的ID生成逻辑
return time.Now().Format("20060102150405") + "-" + randomString(8)
}
// randomString 生成随机字符串
func randomString(length int) string {
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
b := make([]byte, length)
for i := range b {
b[i] = charset[time.Now().UnixNano()%int64(len(charset))]
}
return string(b)
}