【问题标题】:Custom Role Provider has issue with AuthorizeAttribute for MVC自定义角色提供者与 MVC 的 AuthorizeAttribute 存在问题
【发布时间】:2014-11-28 04:30:57
【问题描述】:

我正在开发一个带有自定义角色提供者的 MVC 5 应用程序,但似乎 AuthorizeAttribute 从未调用我的客户角色提供者,我的代码如下:

我的客户提供商:

namespace MyDomain
{
    public class CustomRoleProvider : RoleProvider
    {
         public override string[] GetRolesForUser(string username)
        {
            using (MyContext objContext = new MyContext())
            {
                var objUser = objContext.Users.FirstOrDefault(x => x.Username == username);
                if (objUser == null)
                {
                    return null;
                }
                else
                {
                    string[] ret = { objUser.Access_Levels.Name };
                    return ret;
                }
            }
        }

        public override bool IsUserInRole(string username, string roleName)
        {
            var userRoles = GetRolesForUser(username);
            return userRoles.Contains(roleName);
        }
}

我的控制器:

[Authorize(Roles = "Administrator")]
public class AdminController : Controller

和 Web.Config:

 <system.web>
    <roleManager defaultProvider="CustomRoleProvider" enabled="true" >
      <providers>
        <clear />
        <add name="CustomRoleProvider" type="Online_Storage_Portal.CustomRoleProvider"  cacheTimeoutInMinutes="30"/>
      </providers>
    </roleManager>
  </system.web>

此外,我的自定义角色提供程序与我的其他控制器在同一个项目中,我可以在我的控制器中使用以下代码调用我的自定义角色提供程序方法

String[] 角色 = Roles.GetRolesForUser(用户名)

但具有 [Authorize(Roles = "Administrator")] 的控制器总是将页面重定向到登录屏幕,即使用户登录名和角色都受到重视。

请帮忙!!

【问题讨论】:

    标签: model-view-controller provider role authorize-attribute


    【解决方案1】:

    我相信我已经找到了问题的根源。我将假设您正在使用 Windows 身份验证,并尝试使用您的自定义角色提供程序来代替自动加载的 Windows 组。查看 MVC AuthorizeAttribute 源代码,您会发现它实际上是在调用 Principal.IsInRole。根据 MSDN:

    InRole 首先检查 IsRoleListCached 属性以确定当前用户的缓存角色名称列表是否可用。如果 IsRoleListCached 属性为 true,则检查缓存列表中的指定角色。如果 IsInRole 方法在缓存列表中找到指定角色,则返回 true。 如果 IsInRole 没有找到指定的角色,它会调用默认 Provider 实例的 GetRolesForUser 方法来确定用户名是否与配置的 ApplicationName 值的数据源中的角色相关联。

    所以我猜测,因为 Principal 是 Windows Principal,所以它的角色被填充和缓存。当 IsInRole 被调用时,它会说‘嘿,我已经有了角色,为什么还要回到提供者那里再次获得它们?"

    你可以做的是这样的事情:

    protected void Application_PostAuthenticateRequest(object sender, EventArgs e)
        {
            WindowsIdentity identity = HttpContext.Current.Request.LogonUserIdentity;
            HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(new GenericIdentity(identity.Name), Roles.GetRolesForUser());
        }
    

    这将从 HttpContext 中提取 Windows 身份,使用该名称从您的自定义提供程序中显式获取角色,然后在请求上添加一个新的 GenericPrincipal。我更进一步并实现了一些逻辑来将角色存储在加密的 cookie 中,这样我们就不必在每次请求时都访问角色提供者。

     void Application_PostAuthenticateRequest()
        {
            HttpCookie authCookie = Context.Request.Cookies[FormsAuthentication.FormsCookieName];
            FormsAuthenticationTicket authTicket;
            if (authCookie == null || authCookie.Value == "")
            {
                string[] getRoles = Roles.GetRolesForUser();
                authTicket = new FormsAuthenticationTicket(1,
                    User.Identity.Name,
                    DateTime.Now,
                    DateTime.Now.AddMinutes(20),
                    true,
                    String.Join(";", getRoles));
    
                string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
                authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
                HttpContext.Current.Response.Cookies.Add(authCookie);
            }
            try
            {
                authTicket = FormsAuthentication.Decrypt(authCookie.Value);
            }
            catch
            {
                return;
            }
            string[] roles = authTicket.UserData.Split(';');
            if (Context.User != null)
                Context.User = new System.Security.Principal.GenericPrincipal(Context.User.Identity, roles);
        }
    

    【讨论】:

    • 感谢您的评论丹。除了使用覆盖 WindowsPrincipal IsInRole 方法以提供附加功能的 CustomerPrincipal 之外,我能够做同样的事情。 dotnetfiddle.net/sTU8EQ
    • 这里也一样。丹,你就是那个男人。不知道 post 身份验证、包装 WindowsPrincipal 的概念,或者默认 impl 只是使用缓存角色。
    猜你喜欢
    • 2017-07-26
    • 2011-05-23
    • 1970-01-01
    • 1970-01-01
    • 2013-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-18
    相关资源
    最近更新 更多