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() } }