【问题标题】:User is in role "admin" but [Authorize(Roles="admin")] won't authenticate用户处于角色“admin”但 [Authorize(Roles="admin")] 不会进行身份验证
【发布时间】:2011-03-15 16:19:08
【问题描述】:

我在 SO 描述 how to set up custom user roles 上找到了一个很好的答案,我在我的项目中也做了同样的事情。所以在我的登录服务中,我有:

public ActionResult Login() {
  // password authentication stuff omitted here
  var roles = GetRoles(user.Type); // returns a string e.g. "admin,user"
  var authTicket = new FormsAuthenticationTicket(
                    1,
                    userName,
                    DateTime.Now,
                    DateTime.Now.AddMinutes(20), // expiry
                    false,
                    roles,
                    "/");
  var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, 
    FormsAuthentication.Encrypt(authTicket));
  Response.Cookies.Add(cookie);
  return new XmlResult(xmlDoc); // don't worry so much about this - returns XML as ActionResult
}

在 Global.asax.cs 中,我有(从另一个答案逐字复制):

protected void Application_AuthenticateRequest(Object sender, EventArgs e) {
  var authCookie = Context.Request.Cookies[FormsAuthentication.FormsCookieName];
  if (authCookie != null) {
    var authTicket = FormsAuthentication.Decrypt(authCookie.Value);
    var roles = authTicket.UserData.Split(new Char[] { ',' });
    var userPrincipal = new GenericPrincipal(new GenericIdentity(authTicket.Name), roles);
    Context.User = userPrincipal;
  }
}

然后,在我的ServicesController 课程中,我有:

[Authorize(Roles = "admin")]
//[Authorize]
public ActionResult DoAdminStuff() {
  ...
}

我以具有“管理员”角色的用户身份登录,这很有效。然后我调用 /services/doadminstuff - 我被拒绝访问,即使当我在 Global.asax.cs 中放置一个断点时,我可以看到我的角色确实包括“管理员”。如果我注释掉第一个 Authorize 属性(带有角色)并只使用普通的 Authorize,那么我可以访问该服务。

我一定遗漏了一些重要的东西——但是从哪里开始寻找呢?

【问题讨论】:

    标签: asp.net asp.net-mvc


    【解决方案1】:

    我建议您使用自定义授权属性而不是 Application_AuthenticateRequest

    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
    public class CustomAuthorizeAttribute : AuthorizeAttribute
    {
        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            string cookieName = FormsAuthentication.FormsCookieName;
    
            if (!filterContext.HttpContext.User.Identity.IsAuthenticated ||
                filterContext.HttpContext.Request.Cookies == null ||
                filterContext.HttpContext.Request.Cookies[cookieName] == null
            )
            {
                HandleUnauthorizedRequest(filterContext);
                return;
            }
    
            var authCookie = filterContext.HttpContext.Request.Cookies[cookieName];
            var authTicket = FormsAuthentication.Decrypt(authCookie.Value);
            string[] roles = authTicket.UserData.Split(',');
    
            var userIdentity = new GenericIdentity(authTicket.Name);
            var userPrincipal = new GenericPrincipal(userIdentity, roles);
    
            filterContext.HttpContext.User = userPrincipal;
            base.OnAuthorization(filterContext);
        }
    }
    

    然后:

    [CustomAuthorize(Roles = "admin")]
    public ActionResult DoAdminStuff() 
    {
        ...
    }
    

    另外一件非常重要的事情是确保在您登录时发出一个身份验证 cookie,因为您返回一个 XML 文件。当您尝试访问 url /services/doadminstuff 时,使用 FireBug 检查是否正确发送了身份验证 cookie。

    【讨论】:

    • 成功了!谢谢!告诉我,为什么这行得通,但 Global.asax.cs 中的那个不行?
    • 再次感谢您的帮助!也许您也可以对这个相关问题有所了解:stackoverflow.com/q/6586156/7850
    • 谢谢,它有效。以及如何进一步控制要显示的页面和正确的消息。
    【解决方案2】:

    我会首先更改委托人分配:

    Thread.CurrentPrincipal = userPrincipal;
    if (HttpContext.Current != null)
    {
        HttpContext.Current.User = userPrincipal;
    }
    

    作为 ASP.NET 文档的立场。

    【讨论】:

      猜你喜欢
      • 2019-12-30
      • 2021-01-11
      • 1970-01-01
      • 2019-02-16
      • 1970-01-01
      • 2018-05-28
      • 1970-01-01
      • 2020-05-21
      • 2020-09-18
      相关资源
      最近更新 更多