You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#类库中类与方法的自定义权限验证属性最佳实践咨询

更优的权限验证最佳实践

你当前在服务构造函数中通过自定义属性做权限验证的方式,存在职责不清晰、灵活性不足的问题(构造函数核心职责是初始化对象,而非业务级别的权限校验),以下是几个更合理的实践方案:

1. 抽离权限验证到独立授权服务

  • 定义专门的IAuthorizationService接口,封装权限校验逻辑:
    public interface IAuthorizationService
    {
        void ValidateAccess(IToken token, params UserLevel[] allowedLevels);
        // 也可以返回bool+错误信息,避免直接抛异常,让调用方决定处理方式
        bool TryValidateAccess(IToken token, params UserLevel[] allowedLevels, out string errorMessage);
    }
    
    public class AuthorizationService : IAuthorizationService
    {
        public void ValidateAccess(IToken token, params UserLevel[] allowedLevels)
        {
            if (token == null || !allowedLevels.Contains(token.UserLevel))
            {
                throw new UnauthorizedAccessException("当前用户级别无权访问该服务");
            }
        }
    }
    
  • 各个服务类依赖IAuthorizationService,在业务方法执行前调用验证逻辑,而非构造函数:
    public class JokerService
    {
        private readonly IAuthorizationService _authService;
        private readonly IToken _token;
    
        public JokerService(IAuthorizationService authService, IToken token)
        {
            _authService = authService;
            _token = token;
        }
    
        public void DoJokerStuff()
        {
            // 方法执行前校验权限
            _authService.ValidateAccess(_token, UserLevel.UserGoer, UserLevel.UserMaker);
            // 业务逻辑...
        }
    }
    
    这种方式把权限校验和服务初始化分离,职责更清晰,也支持不同方法配置不同权限的场景。

2. 结合属性标记与装饰器模式实现AOP校验

  • 自定义权限标记属性:
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
    public class AuthorizeAttribute : Attribute
    {
        public UserLevel[] AllowedLevels { get; }
    
        public AuthorizeAttribute(params UserLevel[] allowedLevels)
        {
            AllowedLevels = allowedLevels;
        }
    }
    
  • 给服务类创建装饰器,统一拦截方法调用并校验权限(可以用Castle DynamicProxy等第三方库实现动态代理,或者手动写装饰器):
    public class JokerServiceDecorator : IJokerService
    {
        private readonly IJokerService _innerService;
        private readonly IAuthorizationService _authService;
        private readonly IToken _token;
    
        public JokerServiceDecorator(IJokerService innerService, IAuthorizationService authService, IToken token)
        {
            _innerService = innerService;
            _authService = authService;
            _token = token;
        }
    
        [Authorize(UserLevel.UserGoer, UserLevel.UserMaker)]
        public void DoJokerStuff()
        {
            // 读取方法上的权限属性并校验
            var attribute = typeof(IJokerService).GetMethod(nameof(DoJokerStuff))
                .GetCustomAttribute<AuthorizeAttribute>();
            if (attribute != null)
            {
                _authService.ValidateAccess(_token, attribute.AllowedLevels);
            }
            _innerService.DoJokerStuff();
        }
    }
    
    这种方式可以避免在每个方法里重复写校验代码,通过AOP统一处理权限,扩展性更强。

3. 服务-权限映射+工厂模式

  • 在类库初始化时,注册服务类型与允许级别映射:
    public static class ServiceAuthorizationConfig
    {
        public static Dictionary<Type, UserLevel[]> ServiceToAllowedLevels { get; } = new()
        {
            { typeof(JokerService), new[] { UserLevel.UserGoer, UserLevel.UserMaker } },
            // 其他服务映射...
        };
    }
    
  • 实现服务工厂,在创建服务实例前先校验权限:
    public class ServiceFactory
    {
        private readonly IAuthorizationService _authService;
    
        public ServiceFactory(IAuthorizationService authService)
        {
            _authService = authService;
        }
    
        public T CreateService<T>(IToken token) where T : class
        {
            // 校验当前服务的权限
            if (ServiceAuthorizationConfig.ServiceToAllowedLevels.TryGetValue(typeof(T), out var allowedLevels))
            {
                _authService.ValidateAccess(token, allowedLevels);
            }
            // 创建服务实例(可结合依赖注入容器)
            return Activator.CreateInstance(typeof(T), token) as T;
        }
    }
    
    这种方式把权限校验前置到服务创建环节,确保只有权限符合的用户能拿到服务实例,避免后续调用时才报错。

关于构造函数校验的不足

构造函数中做权限校验的问题在于:

  • 违反单一职责:构造函数核心是初始化对象,混入业务校验逻辑会让类的职责变杂,不利于测试和维护。
  • 灵活性差:如果服务中部分方法需要不同权限,构造函数校验无法区分,只能统一限制整个服务。
  • 调试难度高:构造函数抛出异常会导致对象创建失败,难以定位是初始化问题还是权限问题。

内容的提问来源于stack exchange,提问作者Fatih

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 19:40:27