ASP.NET MVC – Comment afficher des erreurs non autorisées sur la page de connexion?

Dans mon application ASP.NET MVC, la plupart des contrôleurs sont décorés avec

[Authorize(Roles="SomeGroup")] 

Lorsqu’un utilisateur n’est pas autorisé à accéder à quelque chose, il est envoyé à “~ / Login”, qui est l’action de connexion sur mon contrôleur de compte.

Comment puis-je déterminer qu’un utilisateur a atteint la page de connexion car il n’est pas autorisé à afficher une erreur appropriée?

Vous pouvez rechercher la valeur ?ReturnUrl= queryssortingng ou créer votre propre filtre d’autorisation et définir un champ dans TempData indiquant la raison.

Voici un simple filtre personnalisé qui fera l’affaire:

 [AtsortingbuteUsage(AtsortingbuteTargets.Class | AtsortingbuteTargets.Method)] public class CustomAuthorizeAtsortingbute : AuthorizeAtsortingbute { // NOTE: This is not thread safe, it is much better to store this // value in HttpContext.Items. See Ben Cull's answer below for an example. private bool _isAuthorized; protected override bool AuthorizeCore(System.Web.HttpContextBase httpContext) { _isAuthorized = base.AuthorizeCore(httpContext); return _isAuthorized; } public override void OnAuthorization(AuthorizationContext filterContext) { base.OnAuthorization(filterContext); if(!_isAuthorized) { filterContext.Controller.TempData.Add("RedirectReason", "Unauthorized"); } } } 

Ensuite, à votre avis, vous pouvez faire quelque chose comme ceci:

 @if(TempData["RedirectReason"] == "Unauthorized") { You don't have permission to access that area } 

(Bien que je recommande une meilleure approche que ces chaînes magiques, mais vous obtenez le point)

MISE À JOUR (juin 2015): @ daniel-lidström a correctement signalé que vous ne devriez pas utiliser Response.Redirect dans une application ASP.NET MVC. Pour plus d’informations sur pourquoi, veuillez consulter ce lien: Response.Redirect et ASP.NET MVC – Ne pas mélanger .

MISE À JOUR (sept. 2014): Je ne suis pas sûr que HandleUnauthorizedRequest ait été ajouté à AuthorizeAtsortingbute, mais de toute façon, j’ai pu affiner le code AuthorizeRedirect en quelque chose de plus petit et plus simple.

 [AtsortingbuteUsage(AtsortingbuteTargets.Class | AtsortingbuteTargets.Method)] public class AuthorizeRedirect : AuthorizeAtsortingbute { public ssortingng RedirectUrl = "~/Error/Unauthorized"; protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) { base.HandleUnauthorizedRequest(filterContext); if (filterContext.RequestContext.HttpContext.User.Identity.IsAuthenticated) { filterContext.Result = new RedirectResult(RedirectUrl); } } } 

Réponse originale ci-dessous (toujours entièrement fonctionnel)

J’ai laissé cette réponse ici car elle vous donne encore un aperçu de la manière dont fonctionne le pipeline d’autorisation.

Pour quiconque atterrit encore ici, j’ai édité la réponse de Ben Scheirman pour redirect automatiquement vers une page non autorisée lorsque l’utilisateur est connecté mais n’est pas autorisé. Vous pouvez modifier le chemin de redirection à l’aide du paramètre de nom RedirectUrl.

EDIT: J’ai mis la solution en sécurité grâce aux conseils de Tarynn et MSDN

 [AtsortingbuteUsage(AtsortingbuteTargets.Class | AtsortingbuteTargets.Method)] public class AuthorizeRedirect : AuthorizeAtsortingbute { private const ssortingng IS_AUTHORIZED = "isAuthorized"; public ssortingng RedirectUrl = "~/error/unauthorized"; protected override bool AuthorizeCore(System.Web.HttpContextBase httpContext) { bool isAuthorized = base.AuthorizeCore(httpContext); httpContext.Items.Add(IS_AUTHORIZED, isAuthorized); return isAuthorized; } public override void OnAuthorization(AuthorizationContext filterContext) { base.OnAuthorization(filterContext); var isAuthorized = filterContext.HttpContext.Items[IS_AUTHORIZED] != null ? Convert.ToBoolean(filterContext.HttpContext.Items[IS_AUTHORIZED]) : false; if (!isAuthorized && filterContext.RequestContext.HttpContext.User.Identity.IsAuthenticated) { filterContext.RequestContext.HttpContext.Response.Redirect(RedirectUrl); } } } 

La méthode de Ben Cull fonctionne bien, mais rappelez-vous qu’il existe deux classes AuthorizeAtsortingbute – une dans System.Web.HTTP (utilisée par l’API Web) et l’autre dans System.Web.Mvc. La méthode de Ben utilise la classe System.Web.Mvc. Pour plus de clarté, je suggère d’utiliser le chemin complet.

Si vous utilisez Web API avec MVC, vous devrez implémenter deux filtres:

 public class AuthorizeRedirectMVCAtsortingbute : System.Web.Mvc.AuthorizeAtsortingbute { protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) { base.HandleUnauthorizedRequest(filterContext); if (filterContext.RequestContext.HttpContext.User.Identity.IsAuthenticated) { filterContext.Result = new RedirectResult("~/Account/AccessDenied"); } } } public class AuthorizeRedirectAPIAtsortingbute : System.Web.Http.AuthorizeAtsortingbute { protected override void HandleUnauthorizedRequest(HttpActionContext actionContext) { base.HandleUnauthorizedRequest(actionContext); if (actionContext.RequestContext.Principal.Identity.IsAuthenticated) { actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Forbidden); } } } 

Notez qu’asp.net vous permettra de décorer votre contrôleur MVC avec un filtre API – cela ne fonctionnera pas comme vous le souhaitez, alors gardez vos noms d’atsortingbuts explicites.

Si vous avez un contrôleur et que vous ne voulez pas avoir une URL dans votre code, vous pouvez également redirect cette méthode. Il ne changera pas l’URL dans la barre d’adresse du navigateur afin que l’utilisateur ne verra jamais l’URL de la page non autorisée. Cela a été écrit dans MVC 3. Cette méthode fonctionnera également si vous souhaitez les redirect vers une page de connexion ou si vous souhaitez les redirect vers une page pour leur dire qu’ils ne sont pas autorisés. J’avais une section dans le programme sur laquelle certains utilisateurs n’avaient pas de droits mais ils étaient connectés, c’est ce que j’ai utilisé.

 public class AuthorizedRedirect : AuthorizeAtsortingbute { protected override bool AuthorizeCore(HttpContextBase httpContext) { bool isAuthorized = base.AuthorizeCore(httpContext); return isAuthorized; } protect override void HandleUnauthorizedRequest(AuthorizationContext filterContext) { filterContext.RequestContext.RouteData.Values["controller"] = "error"; filterContext.Result = new ViewResult { ViewName = "unauthorized" }; } 

Et une version encore plus simple qui utilise les parameters de FormsAuthentication. Pour ceux qui ne sont pas familiers avec Contract, Contract.Requires est un ajout .NET 4. Avantages et inconvénients de l’utilisation de contrats de code .

 public class RequiresAtsortingbute : AuthorizeAtsortingbute { protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) { Contract.Requires(filterContext != null); HttpContextBase context = filterContext.RequestContext.HttpContext; if (context.User.Identity.IsAuthenticated) { // user does not possess the required role permission ssortingng url = context.GetCustomErrorUrl(401); context.Response.Redirect(url); } else { // redirect the user to the login page ssortingng extraQuerySsortingng = context.Request.RawUrl; FormsAuthentication.RedirectToLoginPage(extraQuerySsortingng); } } } 

En allant plus loin de la réponse de divide_byzero même si vous n’avez pas de contrôleur, vous pouvez toujours utiliser le HandleUnauthorizedRequest pour modifier la redirection.

 [AtsortingbuteUsage(AtsortingbuteTargets.Class | AtsortingbuteTargets.Method)] public class AuthoriseRedirect : AuthorizeAtsortingbute { protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) { filterContext.RequestContext.HttpContext.Response.Redirect("UrlToRedirectTo"); } } 

Pratique si vous possédez un site Webforms hérité que vous allez convertir en MVC sur une période de temps plus longue …..!

J’aime ce que Brian Vander Plaats a posté, juste ajouté quelques améliorations:

 ///  /// Authorize or redirect to an unauthorized MVC action if the user does not have the required roles /// (an unauthenticated user will be redirected to the defualt sign in action) /// Decorate an action or a controller like this [AuthorizeAndRedirect(Roles = "RoleName")] ///  [AtsortingbuteUsage(AtsortingbuteTargets.Class | AtsortingbuteTargets.Method, Inherited = true, AllowMultiple = false)] public class AuthorizeOrRedirectAtsortingbute : System.Web.Mvc.AuthorizeAtsortingbute { protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) { base.HandleUnauthorizedRequest(filterContext); if (filterContext.RequestContext.HttpContext.User.Identity.IsAuthenticated) { var routeData = new RouteData(); routeData.Values.Add("controller", "Error"); routeData.Values.Add("action", "Unauthorized"); filterContext.Result = new RedirectToRouteResult(routeData.Values); } } } ///  /// Authorize or redirect to an unauthorized API action if the user does not have the required roles /// (an unauthenticated user will be redirected to the defualt sign in action) /// Decorate an action or a controller like this [AuthorizeAndRedirect(Roles = "RoleName")] ///  [AtsortingbuteUsage(AtsortingbuteTargets.Class | AtsortingbuteTargets.Method, Inherited = true, AllowMultiple = false)] public class AuthorizeOrRedirectApiFilterAtsortingbute : System.Web.Http.AuthorizeAtsortingbute { protected override void HandleUnauthorizedRequest(HttpActionContext actionContext) { base.HandleUnauthorizedRequest(actionContext); if (actionContext.RequestContext.Principal.Identity.IsAuthenticated) { actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized); } } }