package middleware import ( "strings" "affiliate_dash/internal/model" "affiliate_dash/internal/pkg/jwt" "affiliate_dash/internal/pkg/response" "affiliate_dash/internal/service" "github.com/gin-gonic/gin" ) const ( CtxUserID = "user_id" CtxUsername = "username" CtxRole = "role" CtxMerchantRole = "merchant_role" CtxMerchantPermissions = "merchant_permissions" ) func Auth(jm *jwt.Manager) gin.HandlerFunc { return func(c *gin.Context) { auth := c.GetHeader("Authorization") if auth == "" { response.Unauthorized(c, "未登录") c.Abort() return } parts := strings.SplitN(auth, " ", 2) if len(parts) != 2 || !strings.EqualFold(parts[0], "Bearer") { response.Unauthorized(c, "无效的认证头") c.Abort() return } claims, err := jm.Parse(parts[1]) if err != nil { response.Unauthorized(c, "登录已过期,请重新登录") c.Abort() return } c.Set(CtxUserID, claims.UserID) c.Set(CtxUsername, claims.Username) c.Set(CtxRole, claims.Role) c.Next() } } func RequireRole(roles ...string) gin.HandlerFunc { set := make(map[string]struct{}, len(roles)) for _, r := range roles { set[r] = struct{}{} } return func(c *gin.Context) { role, _ := c.Get(CtxRole) roleStr, _ := role.(string) if _, ok := set[roleStr]; !ok { response.Forbidden(c, "权限不足") c.Abort() return } c.Next() } } func GetUserID(c *gin.Context) uint { v, _ := c.Get(CtxUserID) id, _ := v.(uint) return id } func GetRole(c *gin.Context) string { v, _ := c.Get(CtxRole) role, _ := v.(string) return role } // Tenant 根据 X-Merchant-ID(商户 ID 或编码)解析当前后台请求所属商户。 // 未指定时选择该账号的默认商户,确保旧后台继续落到“自营商户”。 func Tenant(tenantSvc *service.TenantService) gin.HandlerFunc { return func(c *gin.Context) { merchantRef := c.GetHeader("X-Merchant-ID") if GetRole(c) == model.RoleAdmin && merchantRef != "" { merchant, err := tenantSvc.ResolveMerchantForAdmin(merchantRef) if err != nil { response.Forbidden(c, err.Error()) c.Abort() return } c.Set(CtxMerchantID, merchant.ID) c.Set(CtxMerchantRole, model.MemberRoleOwner) permissions, _ := tenantSvc.MerchantRolePermissions(merchant.ID, model.MemberRoleOwner) c.Set(CtxMerchantPermissions, permissions) c.Next() return } member, err := tenantSvc.ResolveMember(GetUserID(c), merchantRef) if err != nil { response.Forbidden(c, err.Error()) c.Abort() return } c.Set(CtxMerchantID, member.MerchantID) c.Set(CtxMerchantRole, member.Role) permissions, err := tenantSvc.MerchantRolePermissions(member.MerchantID, member.Role) if err != nil { response.Forbidden(c, err.Error()) c.Abort() return } c.Set(CtxMerchantPermissions, permissions) c.Next() } } func RequireMerchantRole(roles ...string) gin.HandlerFunc { allowed := make(map[string]struct{}, len(roles)) for _, role := range roles { allowed[role] = struct{}{} } return func(c *gin.Context) { value, _ := c.Get(CtxMerchantRole) role, _ := value.(string) if _, ok := allowed[role]; !ok { response.Forbidden(c, "商户权限不足") c.Abort() return } c.Next() } } // RequireMerchantPermissions 按当前商户的角色权限校验。保留角色通过兼容权限集计算, // 自定义角色从 merchant_roles 读取,所有列出的权限均需具备。 func RequireMerchantPermissions(tenantSvc *service.TenantService, permissions ...string) gin.HandlerFunc { return func(c *gin.Context) { granted := GetMerchantPermissions(c) for _, permission := range permissions { if _, ok := granted[permission]; !ok { response.Forbidden(c, "商户权限不足") c.Abort() return } } c.Next() } } func GetMerchantPermissions(c *gin.Context) map[string]struct{} { value, _ := c.Get(CtxMerchantPermissions) permissions, _ := value.(map[string]struct{}) return permissions } func GetMerchantRole(c *gin.Context) string { value, _ := c.Get(CtxMerchantRole) role, _ := value.(string) return role }