Files
junhong_cmp_fiber/pkg/middleware/permission.go
huang 6821e5abcf
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 4m36s
refactor: 统一错误消息数据源,优化错误码与映射表管理
主要改动:
- 改造 errors.New() 和 Wrap() 函数签名为可变参数,优先使用 errorMessages 映射表
- 添加 allErrorCodes 注册表和 init() 启动时校验,确保错误码与映射表一致
- 添加 TestAllCodesHaveMessages 和 TestNoOrphanMessages 测试防止映射表腐化
- 清理 109 处与映射表一致的冗余硬编码(service 层)
- 保留业务特定消息覆盖能力

新增 API 用法:
- errors.New(errors.CodeUnauthorized) // 使用映射表默认消息
- errors.New(errors.CodeNotFound, "提现申请不存在") // 覆盖为自定义消息
2026-01-22 18:27:42 +08:00

185 lines
5.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package middleware
import (
"context"
"github.com/break/junhong_cmp_fiber/pkg/constants"
"github.com/break/junhong_cmp_fiber/pkg/errors"
"github.com/gofiber/fiber/v2"
)
// PermissionChecker 权限检查器接口
// 用于查询用户的权限列表
type PermissionChecker interface {
// CheckPermission 检查用户是否拥有指定权限
// userID: 用户ID
// permCode: 权限编码
// platform: 端口类型 (all/web/h5)
CheckPermission(ctx context.Context, userID uint, permCode string, platform string) (bool, error)
}
// PermissionConfig 权限校验中间件配置
type PermissionConfig struct {
// PermissionChecker 权限检查器
PermissionChecker PermissionChecker
// Platform 端口类型 (all/web/h5)
// 如果为空,默认为 "all"
Platform string
// SkipSuperAdmin 是否跳过超级管理员的权限检查
// 默认为 true
SkipSuperAdmin bool
}
// RequirePermission 权限校验中间件
// 检查当前用户是否拥有指定权限
// 如果没有权限,返回 403 错误
func RequirePermission(permCode string, config PermissionConfig) fiber.Handler {
return func(c *fiber.Ctx) error {
// 获取用户信息
userID := GetUserIDFromContext(c.UserContext())
if userID == 0 {
return errors.New(errors.CodeUnauthorized, "未认证的请求")
}
// 如果配置为跳过超级管理员,且当前用户是超级管理员,则跳过权限检查
if config.SkipSuperAdmin {
userType := GetUserTypeFromContext(c.UserContext())
if userType == constants.UserTypeSuperAdmin {
return c.Next()
}
}
// 确定端口类型
platform := config.Platform
if platform == "" {
platform = constants.PlatformAll
}
// 检查权限检查器是否已配置
if config.PermissionChecker == nil {
return errors.New(errors.CodeInternalError, "权限检查器未配置")
}
// 检查用户是否拥有该权限
hasPermission, err := config.PermissionChecker.CheckPermission(c.UserContext(), userID, permCode, platform)
if err != nil {
// 如果是 AppError直接返回
if appErr, ok := err.(*errors.AppError); ok {
return appErr
}
// 否则包装为 AppError
return errors.Wrap(errors.CodeInternalError, err, "权限检查失败")
}
if !hasPermission {
return errors.New(errors.CodeForbidden, "无权限访问该资源")
}
return c.Next()
}
}
// RequireAnyPermission 检查用户是否拥有指定权限列表中的任意一个权限
// 如果没有任何权限,返回 403 错误
func RequireAnyPermission(permCodes []string, config PermissionConfig) fiber.Handler {
return func(c *fiber.Ctx) error {
// 获取用户信息
userID := GetUserIDFromContext(c.UserContext())
if userID == 0 {
return errors.New(errors.CodeUnauthorized, "未认证的请求")
}
// 如果配置为跳过超级管理员,且当前用户是超级管理员,则跳过权限检查
if config.SkipSuperAdmin {
userType := GetUserTypeFromContext(c.UserContext())
if userType == constants.UserTypeSuperAdmin {
return c.Next()
}
}
// 确定端口类型
platform := config.Platform
if platform == "" {
platform = constants.PlatformAll
}
// 检查权限检查器是否已配置
if config.PermissionChecker == nil {
return errors.New(errors.CodeInternalError, "权限检查器未配置")
}
// 检查用户是否拥有任意一个权限
for _, permCode := range permCodes {
hasPermission, err := config.PermissionChecker.CheckPermission(c.UserContext(), userID, permCode, platform)
if err != nil {
// 如果是 AppError直接返回
if appErr, ok := err.(*errors.AppError); ok {
return appErr
}
// 否则包装为 AppError
return errors.Wrap(errors.CodeInternalError, err, "权限检查失败")
}
// 如果拥有任意一个权限,则放行
if hasPermission {
return c.Next()
}
}
return errors.New(errors.CodeForbidden, "无权限访问该资源")
}
}
// RequireAllPermissions 检查用户是否拥有指定权限列表中的所有权限
// 如果缺少任意一个权限,返回 403 错误
func RequireAllPermissions(permCodes []string, config PermissionConfig) fiber.Handler {
return func(c *fiber.Ctx) error {
// 获取用户信息
userID := GetUserIDFromContext(c.UserContext())
if userID == 0 {
return errors.New(errors.CodeUnauthorized, "未认证的请求")
}
// 如果配置为跳过超级管理员,且当前用户是超级管理员,则跳过权限检查
if config.SkipSuperAdmin {
userType := GetUserTypeFromContext(c.UserContext())
if userType == constants.UserTypeSuperAdmin {
return c.Next()
}
}
// 确定端口类型
platform := config.Platform
if platform == "" {
platform = constants.PlatformAll
}
// 检查权限检查器是否已配置
if config.PermissionChecker == nil {
return errors.New(errors.CodeInternalError, "权限检查器未配置")
}
// 检查用户是否拥有所有权限
for _, permCode := range permCodes {
hasPermission, err := config.PermissionChecker.CheckPermission(c.UserContext(), userID, permCode, platform)
if err != nil {
// 如果是 AppError直接返回
if appErr, ok := err.(*errors.AppError); ok {
return appErr
}
// 否则包装为 AppError
return errors.Wrap(errors.CodeInternalError, err, "权限检查失败")
}
// 如果缺少任意一个权限,则拒绝访问
if !hasPermission {
return errors.New(errors.CodeForbidden, "无权限访问该资源")
}
}
return c.Next()
}
}