用户处于“admin”角色,但[Authorize(Roles =“admin”)]将不会进行身份验证

时间:2011-03-15 16:19:08

标签: asp.net asp.net-mvc

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

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() {
  ...
}

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

我必须遗漏一些关键的东西 - 但是从哪里开始寻找?

2 个答案:

答案 0 :(得分:17)

我建议您使用自定义授权属性而不是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() 
{
    ...
}

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

答案 1 :(得分:1)

我会先改变主要分配:

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

作为ASP.NET文档。