将WindowsAuthentication与存储在DB中的规则相结合

时间:2013-12-06 15:18:42

标签: c# asp.net-mvc asp.net-mvc-5

我有一个ASP.NET MVC5应用程序,它使用WindowsAuhhentication来验证用户身份。现在我需要为此应用程序添加一个安全层,并希望将其基于标准MVC安全模型并使用AuthorizeAttribute。这依赖于User.IsInRole,但目前这将返回用户所属的组。我不希望将角色存储为AD中的组,而是希望只为每个用户存储在我的数据库中的角色。

所以问题是,我如何覆盖WindowsPrincipal中的IsInRole方法,还是可以创建一个可以满足我想要的CustomPricipal?

我已经找到了很多关于类似主题的信息,但是大多数似乎都参考了MVC4,从我可以收集的内容来看,整个安全模型在MVC4和MVC5之间发生了变化。那么现在最好的方法是什么呢?

非常感谢所有帮助和指示。

干杯迈克

P.S。如果有人知道如何最好地将EF,IOC和缓存融入其中,那么这将是非常好的。

2 个答案:

答案 0 :(得分:0)

我发现MVC5 Asp.Identity与旧的会员提供商相比真的是开发人员友好...这可能是目前缺乏文档的原因。它实际上很直观。

如果您的身份验证规则驻留在数据库中,EntityFramework会将存储过程转换为复杂类型。完成后,您可以创建一个“AuthenticationService”服务层,并根据需要使用DI将复杂类型注入Asp.Identity。

要自定义Asp.Net Identity,您只需向IdentityModels.cs和 AccountViewModels.cs 添加属性,默认情况下,Asp.Identity使用您的 ApplicationDbContext 必须完全没有配置。

此外,您可以通过与 User.IsInRole 类似的方式访问用户信息。

答案 1 :(得分:0)

好的,这就是我所做的。我真的希望人们反馈我可以做出的最佳实践和改进。

  1. 我创建了一个从WindowsPrincipal派生并使用重写的IsInRole方法的新Principal。

    public class QSDPrincipal : WindowsPrincipal
    {
        private readonly IUserService userService;
    
        public QSDPrincipal(WindowsIdentity ntIdentity,
            IUserService userService) :
            base(ntIdentity)
        {
            this.userService = userService;
        }
    
        public override bool IsInRole(string role)
        {
            return userService.CurrentUserIsInRole(role);
        }
    }
    
  2. 这使用DI来填充生活在我的BL层中的userService对象。所以我必须配置容器来正确构建它。

    container.RegisterType<WindowsIdentity>(new HierarchicalLifetimeManager(),
        new InjectionFactory(x => (WindowsIdentity)HttpContext.Current.User.Identity));
    
    container.RegisterType<IPrincipal, QSDPrincipal>(new HierarchicalLifetimeManager());
    
  3. 我使用DependencyResolved在PostAuthenticateRequest事件中创建我的新Principal。

    protected void Application_PostAuthenticateRequest(object sender, EventArgs e)
    {
        var newUser = (IPrincipal)DependencyResolver.Current.GetService(typeof(IPrincipal));
    
        HttpContext.Current.User = newUser;
    }
    
  4. 然后在UserService本身中,我实现了一个方法并实现了一些简单的缓存,因此它只对每个请求进行一次数据库查询。

    public bool CurrentUserIsInRole(string role)
    {
        return CurrentUserRoles.Contains(role);
    }
    
    private IEnumerable<string> currentUserRoles;
    
    public IEnumerable<string> CurrentUserRoles
    {
        get
        {
            if (currentUserRoles == null)
            {
                     var user = GetCurrentUser();
    
                currentUserRoles = new List<string>
                {
                    user.Role.Name
                };
            }
    
            return currentUserRoles;
        }
    }
    
  5. 就是这样,一切似乎都有效。

    非常感谢思想和改进。

    干杯迈克