代码之家  ›  专栏  ›  技术社区  ›  onof

ASP.NET:依赖项注入和角色

  •  2
  • onof  · 技术社区  · 14 年前

    我有一个使用注入的BLL服务的页面:一个简单的服务,返回一组具有如下函数的对象:

    public IMyService { List<Foo> All(); }
    

    有一个针对普通用户的默认实现。 现在,我需要具有管理角色的用户可以通过服务的另一个实现查看更多对象。

    在哪里可以配置页面以使用第二个实现?

    我的第一个解决方案是将依赖项放到页面中的iunitycontainer,并使用它来解决依赖项:

    [Dependency]
    public IUnityContainer Container { get; set;}
    
    Page_Init(..) 
    { 
        _myService = User.IsInRole(MyRoles.Administrators)
                     ? Container.Resolve<IMyService>("forAdmins")
                     : Container.Resolve<IMyService>();
    }
    

    但它非常丑陋:它是一个服务定位器,既不可扩展,也不可测试。

    我该如何处理这种情况?可能为每个角色创建子容器?

    2 回复  |  直到 14 年前
        1
  •  4
  •   Mark Seemann    14 年前

    您可以将其实现为 装饰者 混合成的 :

    public SelectiveService : IMyService
    {
        private readonly IMyService normalService;
        private readonly IMyService adminService;
    
        public SelectiveService(IMyService normalService, IMyService adminService)
        {
            if (normalService == null)
            {
                throw new ArgumentNullException("normalService");
            }
            if (adminService == null)
            {
                throw new ArgumentNullException("adminService");
            }
    
            this.normalService = normalService;
            this.adminService = adminService;
        }
    
        public List<Foo> All()
        {
            if(Thread.CurrentPrincipal.IsInRole(MyRoles.Administrators))
            {
                return this.adminService.All();
            }
            return this.normalService.All();
        }
    }
    

    以下是 单一责任原则 因为每个实现只做一件事。

        2
  •  1
  •   Steven    14 年前

    我同意你现在的设计很难看。我个人不喜欢这种方法,因为您正在页面内设置安全配置。当有人忘记了这一点,以及如何测试此页面配置是否正确时,您将遇到安全错误?

    以下是两个想法: 第一: 使用能够基于用户角色解析该服务的正确实现的工厂:

    public static class MyServiceFactory
    {
        public static IMyService GetServiceForCurrentUser()
        {
            var highestRoleForUser = GetHighestRoleForUser();
    
            Container.Resolve<IMyService>(highestRoleForUser);
        }
    
        private static string GetHighestRoleForUser()
        {
            var roles = Roles.GetRolesForUser().ToList();
            roles.Sort();
            return roles.Last();
        }
    }
    

    第二: 该接口上有多个方法,一个用于普通用户,一个用于管理员。该接口的实现可以 PrincipalPermissionAttribute 在受限方法上定义:

    class MyServiceImpl : IMyService
    {
        public List<Foo> All()
        {
           // TODO
        }
    
        [PrincipalPermission(SecurityAction.Demand, Role ="Administrator")]
        public List<Foo> AllAdmin()
        {
           // TODO
        }
    }
    

    我希望这有帮助。