web-dev-qa-db-fra.com

Rediriger l'accès aux pages non autorisé dans MVC vers la vue personnalisée

J'ai un site Web MVC dans lequel l'accès est basé sur différents rôles. Une fois qu'un utilisateur se connecte au système, il peut voir la navigation vers les pages pour lesquelles il est autorisé. Cependant, certains utilisateurs peuvent toujours essayer d'accéder aux pages à l'aide d'une URL directe. Si tel est le cas, le système les redirige automatiquement vers la page de connexion. Au lieu de la page de connexion, je veux les rediriger vers une autre vue (non autorisée).

Web.Config a l'entrée suivante:

    <customErrors mode="On">
      <error statusCode="401" redirect="~/Home/Unauthorized" />
      <error statusCode="404" redirect="~/Home/PageNotFound" />
    </customErrors>
    <authentication mode="Forms">
<forms name="Development" loginUrl="~/Account/Login" cookieless="UseCookies" timeout="120"></forms>
    </authentication>

J'ai également enregistré ces itinéraires dans Global.asax.cs.

routes.MapRoute(
    name: "Unauthorized",
    url: "{controller}/{action}/{id}",
    defaults: new { controller = "Home", action = "Unauthorized", id = UrlParameter.Optional }
   );


routes.MapRoute(
    name: "PageNotFound",
    url: "{controller}/{action}/{id}",
    defaults: new { controller = "Home", action = "PageNotFound", id = UrlParameter.Optional }
    );

Sera-ce suffisant?

15
user2739418

Avec le changement suivant, cela fonctionne

public class CustomAuthorize : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        //filterContext.Result = new HttpUnauthorizedResult(); // Try this but i'm not sure
          filterContext.Result = new RedirectResult("~/Home/Unauthorized");
    }

    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        if (this.AuthorizeCore(filterContext.HttpContext))
        {
            base.OnAuthorization(filterContext);
        }
        else
        {
            this.HandleUnauthorizedRequest(filterContext);
        }
    }

}

Et puis appliquer sur Controller ou Action comme ci-dessous:

[CustomAuthorize(Roles = "Admin")]

Avec l'approche ci-dessus, je dois revoir tous les contrôleurs/actions et changer l'attribut autorisé! Des tests seront également nécessaires.

Je ne sais toujours pas pourquoi la route Web.Config ne fonctionne pas comme cela a été expliqué dans la documentation MVC. Peut-être que quelque chose a changé dans MVC 4!

17
user2739418

Après quelques recherches, je pense que la réponse la plus simple à ce problème consiste simplement à créer une autorisation personnalisée, très similaire à celle de jbbi (mais celle-ci n'a pas fonctionné car le "nouveau HttpUnauthorizedResult ()" est en interne automatiquement redirigé vers la connexion - au moins en mvc 5 avec identité)

public class CustomAuthorize : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
        {
            //if not logged, it will work as normal Authorize and redirect to the Login
            base.HandleUnauthorizedRequest(filterContext);

        }
        else
        {
            //logged and wihout the role to access it - redirect to the custom controller action
            filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new { controller = "Error", action = "AccessDenied" }));
        }
    }
}

et l'utilisation est la même que l'autorisation par défaut:

[CustomAuthorize(Roles = "Administrator")]

Ensuite, juste pour bien faire les choses, n'oubliez pas d'envoyer le code Http de la page d'erreur. f.e. comme ça dans le contrôleur.

public ActionResult AccessDenied()
{
    Response.StatusCode = 403;
    return View();
}

C'est facile, cela fonctionne et même moi (recrue .net mvc) le comprends.

Remarque: Cela ne fonctionne pas de la même manière avec le code 401 - il prendra toujours le contrôle du 401 et le redirigera en interne vers la connexion. Mais dans mon cas, par définition, la 403 convient également.

28
The Vojtisek

La meilleure façon de gérer cela est probablement de créer un filtre d'action supplémentaire, qui redirige l'utilisateur vers la page d'erreur spécifiée s'il n'appartient pas au rôle spécifié. Ainsi, ces méthodes auront les deux filtres appliqués: [Autoriser] (sans rôle) pour se protéger des utilisateurs non authentifiés et les rediriger vers la page de connexion. Et votre attribut personnalisé avec les rôles. Code SIMILAIRE à ceci (non testé):

public class RoleFilterAttribute : ActionFilterAttribute
{
    public string Role { get; set; }
    public override void OnActionExecuting(ActionExecutingContext ctx)
    {
        // Assume that we have user identity because Authorize is also
        // applied
        var user = ctx.HttpContext.User;
        if (!user.IsInRole(Role))
        {
            ctx.Result = new RedirectResult("url_needed_here");
        }
    }
}

Appliquez à la fois [Autoriser] et [RôleFiltre] aux actions ...

J'espère que cela t'aides!

4
eiximenis

Je pense que vous devriez créer votre propre attribut de filtre d'autorisation qui hérite du filtre d'autorisation par défaut

public class CustomAuthorize: AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
       filterContext.Result = new HttpUnauthorizedResult(); // Try this but i'm not sure
    }
}
2
binard