8

Essentiellement je veux montrer un message amical quand quelqu'un ne fait pas partie d'un rôle listé dans mon attribut. Actuellement, mon application recrée simplement l'utilisateur à l'écran de connexion. J'ai lu quelques articles qui parlent de la création d'un attribut personnalisé qui étend juste [AuthorizeAttribute], mais je pense qu'il doit y avoir quelque chose hors de la boîte pour le faire?Attribut pour la méthode d'action du contrôleur MVC .net

Quelqu'un peut-il me diriger dans la bonne direction de l'endroit où je dois chercher pour ne pas l'envoyer à l'utilisateur sous forme de connexion, mais plutôt leur tirer un message "non autorisé"?

Répondre

2

Si la simplicité ou le contrôle total de la logique est ce que vous voulez, vous pouvez appeler dans votre méthode d'action:

User.IsInRole("NameOfRole"); 

Il retourne un bool et vous pouvez faire le reste de votre logique en fonction de ce résultat.

Un autre que je l'ai utilisé dans certains cas est:

System.Web.Security.Roles.GetRolesForUser(); 

Je pense que renvoie une chaîne [], mais ne me citez pas là-dessus.

EDIT: Un exemple aide toujours ...

public ActionResult AddUser() 
{ 
    if(User.IsInRoles("SuperUser") 
    { 
     return View("AddUser"); 
    } 
    else 
    { 
     return View("SorryWrongRole"); 
    } 
} 

Tant que votre type de retour est "ActionResult" vous pouvez renvoyer les types de retour accepté (ViewResult, PartialViewResult, RedirectResult, JsonResult ...

+0

Donc en utilisant cette logique, je devrais retourner des vues partielles avec des "messages amicaux" corrects? Est-il impossible d'englober toute la méthode d'action avec un attribut qui fait la même chose? – Kyle

+0

J'ai ajouté un exemple ci-dessus. Votre autre option est bien sûr d'écrire votre propre attribut comme vous l'avez mentionné (ce qui serait le plus propre bien que plus difficile à tester unitaire), mais ce n'est certainement pas une approche prête à l'emploi. –

0

Le comportement standard est que l'attribut [Authorize] renvoie un HTTP 401. Le FormsAuthenticationModule (qui est chargé par défaut) intercepte ce 401 et redirige l'utilisateur vers la page de connexion. Jetez un oeil à System.Web.Security.FormsAuthenticationModule :: OnLeave dans Reflector pour voir ce que je veux dire.

Si vous voulez que le AuthorizeAttribute faire quelque chose autre que retour HTTP 401, vous devrez remplacer la méthode AuthorizeAttribute :: HandleUnauthorizedRequest et effectuer votre logique personnalisée là-dedans. Sinon, il suffit de changer cette partie de ~ \ Web.config:

<forms loginUrl="~/Account/LogOn" timeout="2880" /> 

Et faire pointer vers une autre URL, comme ~/AccessDenied.

3

J'ai rencontré ce problème il y a quelques jours et la solution est un peu détaillée mais voici les bits importants. Dans AuthorizeAttribute la méthode OnAuthorization renvoie un HttpUnauthorizedResult lorsque l'autorisation échoue, ce qui rend le renvoi d'un résultat personnalisé un peu difficile. Ce que j'ai fini par faire était de créer une classe CustomAuthorizeAttribute et remplacer la méthode OnAuthorization pour lancer une exception à la place. Je peux ensuite attraper cette exception avec un gestionnaire d'erreur personnalisé et afficher une page d'erreur personnalisée au lieu de renvoyer un 401 (non autorisé).

public class CustomAuthorizeAttribute : AuthorizeAttribute 
{ 
    public virtual void OnAuthorization(AuthorizationContext filterContext) { 
     if (filterContext == null) { 
      throw new ArgumentNullException("filterContext"); 
     } 

     if (AuthorizeCore(filterContext.HttpContext)) { 
      HttpCachePolicyBase cachePolicy = filterContext.HttpContext.Response.Cache; 
      cachePolicy.SetProxyMaxAge(new TimeSpan(0)); 
      cachePolicy.AddValidationCallback(CacheValidateHandler, null /* data */); 
     } 
     else { 
      // auth failed, redirect to login page 
      // filterContext.Result = new HttpUnauthorizedResult(); 

      throw new HttpException ((int)HttpStatusCode.Unauthorized, "Unauthorized");     
     } 
    } 
} 

alors dans votre web.config vous pouvez définir des gestionnaires personnalisés pour les erreurs spécifiques:

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

puis mettre en œuvre votre propre ErrorController pour servir des pages personnalisées.

Sur IIS7, vous devez examiner le paramètre Response.TrySkipIisCustomErrors = true; pour activer vos erreurs personnalisées.

6

Je pourrais être un peu en retard en ajoutant mes 0,02 $, mais lorsque vous créez votre CustomAuthorizationAttribue, vous pouvez utiliser le AuthorizationContext.Result property pour dicter où la méthode AuthorizeAttribute.HandleUnauthorizedRequest dirige l'utilisateur.

Voici un exemple très simple qui vous permet de spécifier l'URL où un utilisateur doit être envoyé après une autorisation a échoué:

public class Authorize2Attribute : AuthorizeAttribute 
{ 
    // Properties 

    public String RedirectResultUrl { get; set; } 

    // Constructors 

    public Authorize2Attribute() 
     : base() 
    { 
    } 

    // Overrides 

    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) 
    { 
     if (String.IsNullOrEmpty(RedirectResultUrl)) 
      base.HandleUnauthorizedRequest(filterContext); 

     else 
      filterContext.Result = new RedirectResult(RedirectResultUrl); 
    } 
} 

Et si je voulais rediriger l'utilisateur vers/Erreur/non autorisée comme suggéré dans un post précédent:

[Authorize2(Roles = "AuthorizedUsers", RedirectResultUrl = "/Error/Unauthorized")] 
public ActionResult RestrictedAction() 
{ 
    // TODO: ... 
} 
+0

J'ai fait une chose similaire, mais je vérifie pour voir si l'utilisateur est authentifié. Cela me permet de rejeter les utilisateurs parce qu'ils ne sont pas dans un rôle, mais ils ne sont pas invités à se connecter –

2

Très similaire à crazyarabian, mais je ne réoriente à ma chaîne si l'utilisateur est authentifié réellement. Cela permet à l'attribut de rediriger vers la page d'ouverture de session standard s'ils ne sont pas actuellement connectés, mais vers une autre page s'ils n'ont pas les autorisations pour accéder à l'URL.

public class EnhancedAuthorizeAttribute : AuthorizeAttribute 
{ 
    public string UnauthorizedUrl { get; set; } 

    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) 
    { 
     var redirectUrl = UnauthorizedUrl; 
     if (filterContext.HttpContext.User.Identity.IsAuthenticated && !string.IsNullOrWhiteSpace(redirectUrl)) 
     { 
      filterContext.Result = new RedirectResult(redirectUrl); 
     } 
     else 
     { 
      base.HandleUnauthorizedRequest(filterContext); 
     } 
    } 
}