2017-06-26 3 views
0

J'ai googlé et stackoverflowed cette question beaucoup et ses différentes variantes, mais je suis encore confus si c'est possible du tout. Je veux juste ajouter un en-tête personnalisé à toutes les actions ayant un attribut spécifique. Cela semble simple? Mais ce n'est pas. Je viens d'écrire ce qui suit:Ajouter un en-tête personnalisé pour une action dans MVC

[AttributeUsage(AttributeTargets.Method)] 
public class HelloWorldAttribute : ActionFilterAttribute 
{ 
    /// <inheritdoc /> 
    public override void OnActionExecuted(ActionExecutedContext filterContext) 
    { 
     filterContext.HttpContext.Response.Headers["X-HelloWorld"] = string.Empty; 
    } 
} 

Et cela fonctionne très bien pour toutes les demandes, sauf si elles sont interdites par [Authorize] au niveau Controller.

J'ai essayé d'utiliser cet attribut pour Controller niveau et passer les noms des méthodes qui doivent ajouter cet en-tête, mais cela ne fonctionne pas aussi. Il semble que Authorize a toujours une priorité plus élevée. Et vous pouvez convenir que c'est moche.

Comment cela peut-il être fait?

+0

Et si vous l'enregistrez globalement? Si pas encore. – dcg

+0

@dcg Je din't parce que j'ai besoin de seulement plusieurs méthodes sur deux contrôleurs. Il est donc plus facile d'avoir une liste blanche de contrôleurs qui doivent ajouter cet en-tête que de l'enregistrer globalement et blaclister tous sauf eux. –

+2

Eh bien, prenez du recul et réfléchissez à ce que vous faites. Pourquoi voudriez-vous que le code de l'en-tête s'exécute quand quelqu'un n'est pas autorisé à voir quelque chose? Par définition, si vous n'êtes pas autorisé, vous ne devriez pas en tirer de fonctionnalité et cela inclura votre en-tête. Ce n'est pas que l'autorisation a une «priorité plus élevée». C'est qu'il exécute plus tôt dans le pipeline afin d'accomplir ce qui précède. – JuanR

Répondre

1

Vous pouvez écrire votre propre attribut d'autorisation, et gérer votre code si la note est autorisée ou vous pouvez ajouter Policy.

Oh je suis soo paresseux ...

ici exemple

Ajouter d'abord la politique

public class ReplaceHeaderPolicy : IAuthorizationRequirement 
{ 

} 

public class ReplaceHeaderHandler : AuthorizationHandler<ReplaceHeaderPolicy> 
{ 
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, ReplaceHeaderPolicy requirement) 
    { 

     if (!context.User.Identity.IsAuthenticated) 
     { 
      var fc = (FilterContext)context.Resource; 
      fc.HttpContext.Response.Headers["X-HelloWorld"] = string.Empty; 
     } 

     context.Succeed(requirement); 
     return Task.CompletedTask; 
    } 
} 

puis enregistrez votre politique

services.AddAuthorization(options => 
     { 
      options.AddPolicy("ReplaceHeader", 
           policy => policy.Requirements.Add(new ReplaceHeaderPolicy())); 
     }); 

     services.AddSingleton<IAuthorizationHandler, ReplaceHeaderHandler>(); 

et de l'utiliser sur le contrôleur

[Authorize] 
    [Authorize(Policy = "ReplaceHeader")] 
    public IActionResult Index() 
    { 
     return View(); 
    } 

Supprimer deuxième [Authorize] pour permettre l'accès pour l'accès non autorisé

J'espère que ça aide

+0

Ajouter plus de détails plutôt référençant l'URL. De [commentaires] (https://stackoverflow.com/review/first-posts/16531641). – harshavmb

1

Le problème est que l'attribut Autorisez est un garde contre la méthode du contrôleur de fait en cours d'exécution afin que votre autre attribut est jamais va courir.

Vous pouvez ajouter un attribut personnalisé comme celui-ci

public class HandleUnauthorizedAttribute : HandleErrorAttribute 
{ 
    public override void OnException(ExceptionContext filterContext) 
    { 
     base.OnException(filterContext); 

     if (filterContext.Exception.GetType() != typeof(SecurityException)) return; 

     var controllerName = (string)filterContext.RouteData.Values["controller"]; 
     var actionName = (string)filterContext.RouteData.Values["action"]; 
     var model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName); 

     filterContext.Result = new ViewResult 
     { 
      ViewName = "Unauthorized", 
      ViewData = new ViewDataDictionary<HandleErrorInfo>(model), 
      TempData = filterContext.Controller.TempData 
     }; 
     filterContext.ExceptionHandled = true; 
     filterContext.HttpContext.Response.Clear(); 
     filterContext.HttpContext.Response.StatusCode = 403; 
     filterContext.HttpContext.Response.Headers.Add("X-HelloWorld", ""); 
     filterContext.HttpContext.Response.TrySkipIisCustomErrors = true; 
    } 
} 

qui traitera l'exception de la sécurité qui se jeter de votre attribut Autorisez. Ou vous pouvez écrire un attribut Authorize personnalisé qui vous ajoute ensuite des en-têtes en réponse.

+0

Malheureusement le flux de contrôle ne tombe pas ici –