主要变更: - 采用 go-zero 框架替代 Gin,提升开发效率 - 重构项目结构,API 文件模块化组织 - 将 model 移至 api/internal/model 目录 - 移除 common 包,改为标准 pkg 目录结构 - 实现统一的仓储模式,支持配置驱动数据库切换 - 简化测试策略,专注 API 集成测试 - 更新 CLAUDE.md 文档,提供详细的开发指导 技术栈更新: - 框架: Gin → go-zero v1.6.0+ - 代码生成: 引入 goctl 工具 - 架构模式: 四层架构 → go-zero 三层架构 (Handler→Logic→Model) - 项目布局: 遵循 Go 社区标准和 go-zero 最佳实践
217 lines
4.7 KiB
Go
217 lines
4.7 KiB
Go
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
|
|
} |