web-dev-qa-db-fra.com

Comment puis-je diffuser une page non autorisée lorsqu'un utilisateur ne se trouve pas dans les rôles autorisés?

J'utilise l'attribut Authorize comme ceci:

[Authorize (Roles="Admin, User")]
Public ActionResult Index(int id)
{
    // blah
}

Lorsqu'un utilisateur ne fait pas partie des rôles spécifiés, j'obtiens une page d'erreur (ressource introuvable). Donc, je mets l'attribut HandleError également.

[Authorize (Roles="Admin, User"), HandleError]
Public ActionResult Index(int id)
{
    // blah
}

Maintenant, il passe à la page Login , si l'utilisateur ne se trouve pas dans les rôles spécifiés.

Comment l'obtenir pour accéder à une page Unauthorized au lieu de la page de connexion, lorsqu'un utilisateur ne remplit pas l'un des rôles requis? Et si une erreur différente se produit, comment la distinguer d'une erreur non autorisée et comment la gérer différemment?

39
Robert Harvey

Ajoutez quelque chose comme ceci à votre web.config:

<customErrors mode="On" defaultRedirect="~/Login">
     <error statusCode="401" redirect="~/Unauthorized" />
     <error statusCode="404" redirect="~/PageNotFound" />
</customErrors>

Vous devez évidemment créer les itinéraires, actions et vues /PageNotFound et /Unauthorized.

EDIT: Je suis désolé, je n’ai apparemment pas bien compris le problème. 

Le problème est que lorsque le filtre AuthorizeAttribute est exécuté, il décide que l'utilisateur ne remplit pas les conditions requises (il/elle peut être connecté, mais son rôle n'est pas correct). Il définit donc le code d'état de la réponse sur 401. Celui-ci est intercepté par le module FormsAuthentication qui effectuera ensuite la redirection.

Je vois deux alternatives: 

  1. Désactiver le defaultRedirect.

  2. Créez votre propre IAuthorizationFilter. Dérivez de AuthorizeAttribute et remplacez HandleUnauthorizedRequest. Dans cette méthode, si l'utilisateur est authentifié, effectuez un redirect vers/Unauthorized

Je n'aime pas non plus: la fonctionnalité defaultRedirect est Nice et pas quelque chose que vous souhaitez implémenter vous-même. La deuxième approche aboutit à ce que l'utilisateur reçoive une page visuellement correcte "Vous n'êtes pas autorisé", mais les codes d'état HTTP ne seront pas les 401 souhaités.

Je ne sais pas assez sur HttpModules pour dire si cela peut être contourné avec un hack tolérable.

EDIT 2 : Que diriez-vous d’implémenter votre propre IAuthorizationFilter de la manière suivante: téléchargez le code MVC2 depuis CodePlex et "empruntez" le code de AuthorizeAttribute. Changez la méthode OnAuthorization pour qu'elle ressemble à

    public virtual void OnAuthorization(AuthorizationContext filterContext)
    {
        if (AuthorizeCore(filterContext.HttpContext))
        { 
            HttpCachePolicyBase cachePolicy = filterContext.HttpContext.Response.Cache;
            cachePolicy.SetProxyMaxAge(new TimeSpan(0));
            cachePolicy.AddValidationCallback(CacheValidateHandler, null /* data */);
        }
        // Is user logged in?
        else if(filterContext.HttpContext.User.Identity.IsAuthenticated)
        {
            // Redirect to custom Unauthorized page
            filterContext.Result = new RedirectResult(unauthorizedUrl);
        } 
        else {
            // Handle in the usual way
            HandleUnauthorizedRequest(filterContext);
        }
    }

unauthorizedUrl est une propriété du filtre ou une lecture de Web.config.

Vous pouvez également hériter de AuthorizeAttribute et remplacer OnAuthorization, mais vous finirez par écrire quelques méthodes privées déjà présentes dans AuthorizeAttribute.

27
Rune

Vous pouvez le faire de deux manières:

  1. Spécifiez l'erreur l'attribut HandleError et donnez une vue à afficher:

    [HandleError (ExceptionType = typeof (UnAuthorizedException), View = "UnauthorizedError")]

Vous pouvez spécifier différents types et vues d'exception.

  1. Créez un ActionFilter personnalisé, recherchez-y les informations d'identification et redirigez-vous vers un contrôleur si l'utilisateur n'est pas autorisé .: http://web.archive.org/web/20090322055514/http://msdn.Microsoft.com/en- us/library/dd381609.aspx
7
Pbirkoff

Peut-être qu'un code d'état 403 est plus approprié en fonction de votre question (l'utilisateur est identifié, mais son compte n'est pas assez privilégié). 401 est pour le cas où vous ne savez pas quels privilèges l'utilisateur a.

4
628426

Et HttpUnauthorizedResult (ceci vient comme une réutilisation de AuthorizeAtrribute) définit simplement StatusCode sur 401. Vous pouvez donc probablement configurer une page 401 dans IIS ou des pages d'erreur personnalisées dans web.config. Bien entendu, vous devez également vous assurer que l'accès à votre page d'erreur personnalisée ne nécessite pas d'autorisation.

3
Mike Chaliy

Remplacez simplement la méthode HandleUnauthorizedRequest de AuthorizeAttribute. Si cette méthode est appelée, mais que l'utilisateur IS est authentifié, vous pouvez rediriger vers votre page "non autorisé".

public class CustomAuthorizeAttribute : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        if (filterContext.HttpContext.User.Identity.IsAuthenticated)
        {
            filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new { Area = "", Controller = "Error", Action = "Unauthorized" }));
        }
        else
        {
            base.HandleUnauthorizedRequest(filterContext);
        }
    }
}
0
Davy