Files

160 lines
4.0 KiB
Go

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
}