2010-07-30 13 views
7

Actualizado: Gracias a la ayuda aquí he creado la siguiente solución:atributo pregunta al usuario para iniciar sesión en lugar de acceso denegado?

public class CustomAuthorize : AuthorizeAttribute 
{ 
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) 
    { 
     // Returns HTTP 401 - see comment in HttpUnauthorizedResult.cs 
     // If user is not logged in prompt 
     if (!filterContext.HttpContext.User.Identity.IsAuthenticated) 
     { 
      base.HandleUnauthorizedRequest(filterContext); 
     } 
     // Otherwise deny access 
     else 
     { 
      filterContext.Result = new RedirectToRouteResult(
       new RouteValueDictionary { 
       {"controller", "Account"}, 
       {"action", "NotAuthorized"} 
      }); 
     } 
    } 
} 

Empecé a partir NerdDinner y estoy usando FormsAuthentication con ActiveDirectory como mi proveedor de pertenencia. He agregado soporte para roles a través de mi base de datos con Global.asax & AccountController (abajo).

Así que ahora en mi controlador tengo mi atributo Autorizar establecido en roles de administrador solamente (abajo). Mi usuario registrado es un autor. Cuando hago clic en eliminar, me pide que inicie sesión, aunque ya lo hice. ¿Dónde puedo poner la lógica para devolver una vista de acceso denegado?

Global.asax.cs

protected void Application_AuthenticateRequest(Object sender, EventArgs e) 
    { 
     HttpCookie authCookie = Context.Request.Cookies[FormsAuthentication.FormsCookieName]; 
     if (authCookie == null || authCookie.Value == "") 
     { 
      return; 
     } 

     FormsAuthenticationTicket authTicket = null; 

     try 
     { 
      authTicket = FormsAuthentication.Decrypt(authCookie.Value); 
     } 
     catch 
     { 
      return; 
     } 

     if (Context.User != null) 
     { 
      string[] roles = authTicket.UserData.Split(new char[] { ';' }); 
      Context.User = new GenericPrincipal(Context.User.Identity, roles); 
     } 
    } 

AccountController.cs

[HttpPost] 
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", 
     Justification = "Needs to take same parameter type as Controller.Redirect()")] 
    public ActionResult LogOn(string userName, string password, bool rememberMe, string returnUrl) 
    { 

     if (!ValidateLogOn(userName, password)) 
     { 
      ViewData["rememberMe"] = rememberMe; 
      return View(); 
     } 

     // Make sure we have the username with the right capitalization 
     // since we do case sensitive checks for OpenID Claimed Identifiers later. 
     userName = this.MembershipService.GetCanonicalUsername(userName); 

     // Lookup user's (CWID) appropriate access level 
     string accessLevel = userRepository.FindUserByUserName(userName).AccessLevel.LevelName; 

     FormsAuthenticationTicket authTicket = new 
         FormsAuthenticationTicket(1, //version 
         userName, // user name 
         DateTime.Now,    //creation 
         DateTime.Now.AddMinutes(30), //Expiration 
         rememberMe, //Persistent 
         accessLevel); // hacked to use roles instead 

     string encTicket = FormsAuthentication.Encrypt(authTicket); 
     this.Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, encTicket)); 

     if (!String.IsNullOrEmpty(returnUrl)) 
     { 
      return Redirect(returnUrl); 
     } 
     else 
     { 
      return RedirectToAction("Index", "Home"); 
     } 
    } 

SpotlightController.cs

[Authorize(Roles="Admin")] 
    public ActionResult Delete(int id) 

Respuesta

5

Esto es lo que hace AuthorizeAttribute, out-of-the-box: verifica si el usuario actual está autorizado para la solicitud actual, y devuelve HHTP 401/UNAUTHORIZED si no lo están, ya sea porque no están registrados en absoluto, o no están en la lista de usuarios/roles autorizados para la solicitud actual.

Web forms authentication HTTP module sees this 401 response, intercepts that, and turns it into an HTTP 302 (redirect) response to the login page, si el atributo loginUrl está configurado en web.config. La idea general es que si a un usuario se le niega el acceso al sitio porque no está conectado, lo próximo que querrá hacer es iniciar sesión.

Como lo que quiere hacer es redirigir a otra parte, sugerencia de Hal de anular HandleUnauthorizedRequest y redirigir no es irrazonable. Solo tenga en cuenta que si aún desea que los usuarios no autenticados vean la página de inicio de sesión (en lugar de autenticarla, pero no en la lista de usuarios/roles permitidos), tendrá que agregar lógica para eso. Aconsejaría contra la idea de anular AuthorizeCore o OnAuthorization; ninguno de estos soluciona realmente el problema, y ​​son mucho más fáciles de arruinar que HandleUnauthorizedRequest.

+0

Craig tiene toda la razón: tendría que manejar la excepción de roles frente a un usuario no autenticado. No creo que eso sea demasiado difícil, pero no lo he intentado así que YMMV. Yo también aconsejaría no meterse con AuthorizeCode o OnAuthorization a menos que realmente desee implementar su propio esquema de autenticación. – Hal

+0

Necesito leer más. Mientras tanto, podría utilizar algo de ayuda para anular HandleUnauthorizedRequest. Entiendo cómo rodar mi propia clase que hereda de AuthorizeAttribute y luego anulo HandleUnauthorizedRequest. No necesito mi propio atributo ya que esto es lo único que estoy cambiando. Entonces, ¿cómo anular HandleUnauthorizedRequest sin derivación? – ryan

+0

Debe derivar un nuevo tipo y anular ese método. Pero ese método es lo único que necesita cambiar. –

2

supongo que se podría derivar de AuthorizeAttribute y luego anular HandleUnauthorizedRequest y poner su propia lógica de redirección allí.

Gracias,

Hal

+0

Supongo que me estoy perdiendo por qué HandleUnauthorizedRequest no hace nada ahora? ¿O simplemente no estoy capturando ese evento? – ryan

+0

¿Has iniciado sesión en un derecho de autor, no en un administrador? El comportamiento deseado es que un usuario con privilegios insuficientes sea redireccionado a una página de excepción, no a una página que intente iniciar sesión con credenciales elevadas (que creo que es el comportamiento predeterminado). ¿Lo entiendo correctamente? – Hal

+0

¡Eso es correcto! – ryan

1

Alternativamente se puede anular el atributo Autorizar. Debería anular el método OnAuthorization y obtener el resultado del método AuthorizeCore de su base. En función de ese resultado, puede lanzar una excepción o una excepción personalizada (es decir, tal vez una excepción de seguridad personalizada que registre el estado) directamente desde OnAuthirziation.

Cuestiones relacionadas