2010-07-30 3 views
7

Mis à jour: Merci à l'aide ici que j'ai créé la solution suivante:attribut demande à l'utilisateur de se connecter au lieu de l'accès refusé?

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"} 
      }); 
     } 
    } 
} 

Je suis parti de NerdDinner et je utilise FormsAuthentication avec ActiveDirectory comme mon fournisseur d'appartenances. J'ai ajouté le support pour les rôles via mon db avec Global.asax & AccountController (ci-dessous).

Alors maintenant, dans mon contrôleur j'ai mon attribut Autorisez défini sur les rôles de seul administrateur (ci-dessous). Mon utilisateur connecté est un auteur. Lorsque je clique sur Supprimer, il me demande de me connecter même si je l'ai déjà fait. Où puis-je mettre la logique pour retourner une vue d'accès refusé?

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) 

Répondre

5

Voici ce que AuthorizeAttribute fait, prêt à l'emploi: Il vérifie si l'utilisateur actuel est autorisé pour la demande en cours et renvoie HHTP 401/NON AUTORISÉ s'ils ne le sont pas, soit parce qu'ils ne sont pas connectés pas du tout, ou ils ne figurent pas dans la liste des utilisateurs/rôles autorisés pour la requête en cours.

Le Web forms authentication HTTP module sees this 401 response, intercepts that, and turns it into an HTTP 302 (redirect) response to the login page, si l'attribut loginUrl est configuré dans web.config. L'idée générale est que si un utilisateur se voit refuser l'accès au site parce qu'il n'est pas connecté, la prochaine chose qu'il veut faire est de se connecter.

Puisque ce que vous voulez faire est de rediriger ailleurs, la suggestion de Hal de HandleUnauthorizedRequest prioritaire et de redirection n'est pas déraisonnable. Il suffit de garder à l'esprit que si vous voulez toujours les utilisateurs non authentifiés pour voir la page de connexion (par opposition à authentifier, mais pas dans la liste des utilisateurs/rôles autorisés), alors vous devrez ajouter une logique pour cela. Je déconseille l'idée de surcharger AuthorizeCore ou OnAuthorization; aucun d'eux ne résout réellement le problème, et ils sont beaucoup plus faciles à bousiller que HandleUnauthorizedRequest.

+0

Craig a tout à fait raison: vous devez gérer l'exception de rôles par rapport à un utilisateur non authentifié. Je ne pense pas que ce serait trop difficile, mais je ne l'ai pas essayé donc YMMV. Je vous déconseillerais aussi de jouer avec AuthorizeCode ou OnAuthorization, sauf si vous voulez vraiment implémenter votre propre schéma d'authentification. – Hal

+0

Je dois lire plus. En attendant, je pourrais utiliser un peu d'aide avec HandleUnauthorizedRequest. Je comprends comment lancer ma propre classe qui hérite de AuthorizeAttribute, puis redéfinir HandleUnauthorizedRequest. Je n'ai pas besoin de mon propre attribut puisque c'est la seule chose qui change. Alors, comment remplacer HandleUnauthorizedRequest sans dériver? – ryan

+0

Vous devez dériver un nouveau type et remplacer cette méthode. Mais cette méthode est la seule chose que vous devez changer. –

2

Je suppose que vous pourriez tirer de AuthorizeAttribute puis remplacer HandleUnauthorizedRequest et mettre votre propre logique de redirection là.

Merci,

Hal

+0

Je suppose que je suis absent pourquoi HandleUnauthorizedRequest ne fait rien maintenant? Ou est-ce que je ne saisis pas cet événement? – ryan

+0

Votre utilisateur connecté dans un droit d'auteur, pas un administrateur? Le comportement souhaité est qu'un utilisateur avec le privilège insuffisant serait redirigé vers une page d'exception, pas une page qui tente de se connecter avec des informations d'identification élevées (qui je crois est le comportement par défaut). Suis-je bien compris? – Hal

+0

C'est correct! – ryan

1

Sinon, vous pouvez remplacer l'attribut Autorisez. Vous devez remplacer la méthode OnAuthorization et obtenir le résultat de la méthode AuthorizeCore à partir de votre base. En fonction de ce résultat, vous pouvez lancer une exception ou une exception personnalisée (c'est-à-dire peut-être une exception de sécurité personnalisée qui enregistre l'état) directement depuis OnAuthirziation.

Questions connexes