2011-03-15 25 views
8

Encontré una gran respuesta en SO describiendo how to set up custom user roles, y he hecho lo mismo en mi proyecto. Así que en mi servicio de sesión que tengo:El usuario tiene el rol "admin" pero [Authorize (Roles = "admin")] no se autenticará

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 
} 

Y en Global.asax.cs, he (copiado textualmente de la otra respuesta):

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; 
    } 
} 

Entonces, en mi clase ServicesController, tengo :

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

Inicio de sesión como usuario con el rol "admin", y eso funciona. Luego llamo/services/doadminstuff, y obtengo acceso denegado, aunque cuando pongo un punto de interrupción en Global.asax.cs, puedo ver que mis roles incluyen "admin". Si comento el primer atributo Authorize (con roles) y solo uso un simple vainilla Authorize, entonces puedo acceder al servicio.

Me falta algo crítico aquí, pero ¿dónde empezar a buscar?

Respuesta

15

le recomiendo que utilice un atributo autorizar personalizada en lugar de 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); 
    } 
} 

y luego:

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

también una cosa muy importante es asegurarse de que cuando se conecta una cookie de autenticación es emitido porque devuelve un archivo XML. Use FireBug para inspeccionar si la cookie de autenticación se envía correctamente cuando intenta acceder a la url /services/doadminstuff.

+3

¡Funcionó! ¡GRACIAS! Dime, ¿por qué funcionó esto, pero el de Global.asax.cs no? –

+1

¡Gracias de nuevo por su ayuda! Tal vez también podría arrojar algo de luz sobre este problema relacionado: http://stackoverflow.com/q/6586156/7850 –

+0

gracias, funciona. y cómo puedo controlar aún más qué página mostrar y con el mensaje correcto. – Timeless

0

que cambiaría asignar principal al principio:

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

como documentación ASP.NET en pie.

Cuestiones relacionadas