用户在角色“管理员”,但[授权(角色=“管理员”)]将不验证

用户在角色“管理员”,但[授权(角色=“管理员”)]将不验证

问题描述:

我发现了一个很好的回答在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中放置断点时,我也可以看到我的角色包含“admin”。如果我注释掉第一个Authorize属性(包含角色)并仅使用简单的香草Authorize,那么我可以访问该服务。

我必须在这里丢失重要的东西 - 但从哪里开始寻找?

我会建议你使用自定义的授权属性,而不是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是否已正确发送。

+3

它的工作!谢谢!告诉我,为什么这个工作,但Global.asax.cs中没有? – 2011-03-15 16:32:05

+1

再次感谢您的帮助!也许你也可以解释一下这个相关的问题:http://*.com/q/6586156/7850 – 2011-07-05 16:57:01

+0

谢谢,它的工作原理。我怎样才能进一步控制显示哪个页面和正确的消息。 – Timeless 2014-07-18 06:30:11

我将在第一个改变主要分配:

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

为ASP.NET文件表示。