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)
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
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
Debe derivar un nuevo tipo y anular ese método. Pero ese método es lo único que necesita cambiar. –