Maison > Article > développement back-end > La séquence d'utilisation et d'exécution de Filter dans Asp.Net WebAPI (Favoris)
Dans WEB Api, l'idée de programmation orientée aspect (AOP) est introduite, et des filtres spécifiques peuvent être insérés à certains endroits pour le traitement d'interception des processus. L'introduction de ce mécanisme permet de mieux mettre en œuvre l'idée DRY (Don't Repeat Yourself). Grâce au filtre, certaines logiques courantes peuvent être traitées de manière uniforme, telles que : la vérification des autorisations, le cryptage et le déchiffrement des paramètres, la vérification des paramètres, etc. peut être utilisé pour un traitement unifié. Aujourd'hui, nous allons présenter le développement et l'utilisation de Filter et discuter de leur séquence d'exécution.
1. Développement et appel du filtre
Dans le WebApi par défaut, le framework propose trois types de filtres. Leurs fonctions et conditions de fonctionnement sont indiquées dans le tableau suivant. :
Filtre Filter 类型 实现的接口 描述 Authorization IAuthorizationFilter 最先运行的Filter,被用作请求权限校验 Action IActionFilter 在Action运行的前、后运行 Exception IExceptionFilter 当异常发生的时候运行 |
Interface implémentée |
Description |
||||||||||||
Autorisation | IAuthorizationFilter | Le premier à s'exécuterFiltre, utilisé pour demander la vérification de l'autorisation | tr>||||||||||||
Action | IActionFilter | DansActionAvant et après opération | ||||||||||||
Exception | IExceptionFilter | Exécuter lorsqu'une exception se produit |
Tout d'abord, nous implémentons un AuthorizatoinFilter qui peut être utilisé pour un contrôle simple des autorisations :
(actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute> verifyResult = actionContext.Request.Headers.Authorization!= && == ; (!= HttpError(
Un filtre simple pour la vérification de l'utilisateur est développé. Ce filtre nécessite que la demande de l'utilisateur contienne l'en-tête Authorization. Le paramètre est 123456. S'il réussit, il sera publié. S'il ne réussit pas, il renverra une erreur 401 et indiquera que le jeton est incorrect dans le contenu. Ensuite, nous devons enregistrer ce filtre. Il existe trois façons d'enregistrer un filtre :
La première façon : placez l'AuthFilterAttribute sur l'action dont nous voulons contrôler les autorisations :
public class PersonController : ApiController { [AuthFilter] public CreateResult Post(CreateUser user) { return new CreateResult() {Id = "123"}; } }
Ceci. manière adaptée au contrôle des autorisations d’une seule action.
La deuxième méthode consiste à trouver le contrôleur correspondant et à ajouter cet attribut :
[AuthFilter] public class PersonController : ApiController { public CreateResult Post(CreateUser user) { return new CreateResult() {Id = "123"}; } }
Cette méthode convient pour contrôler l'ensemble du contrôleur. Après avoir ajouté cet attribut, toutes les actions de l'ensemble du contrôleur. sera obtenu.
La troisième méthode consiste à rechercher App_StartWebApiConfig.cs et à ajouter une instance de filtre sous la méthode Register :
{ id =
Cette méthode convient au contrôle de toutes les API et est acceptée par n'importe quel contrôleur et n'importe quel Action. Ce contrôle d'autorisation.
Dans la plupart des scénarios, la logique de vérification des autorisations de chaque API est la même. Dans ce principe, il s'agit de la méthode la plus simple et la plus pratique pour utiliser l'enregistrement global du filtre. Cependant, il existe un problème évident : s'il est certain. utilisateurs Que dois-je faire si une API ne nécessite pas de contrôle (comme une connexion) ? Nous pouvons le faire sur une telle API :
[AllowAnonymous]public CreateResult PostLogin(LoginEntity entity) { //TODO:添加验证逻辑 return new CreateResult() {Id = "123456"}; }
J'ai marqué AllowAnonymousAttribute pour cette action, et la logique de vérification a ignoré cette API sans effectuer de vérification des autorisations.
Dans le développement réel, nous pouvons concevoir un mécanisme similaire à Session pour obtenir un jeton via la connexion de l'utilisateur, ajouter l'en-tête Authorization et apporter ce jeton dans les requêtes HTTP interactives ultérieures, et personnaliser Pour vérifier le jeton dans AuthFilterAttribute, un Un processus standard de vérification des jetons peut être mis en œuvre.
Ensuite, nous introduisons ActionFilter :
ActionFilterAttrubute fournit deux méthodes d'interception : OnActionExecuting et OnActionExecuted, qui fournissent toutes deux des méthodes synchrones et asynchrones.
La méthode OnActionExecuting est exécutée avant l'exécution de l'action, et la méthode OnActionExecuted est exécutée après l'exécution de l'action.
Examinons un scénario d'application : les étudiants qui ont utilisé MVC doivent être familiers avec la liaison de modèle et la vérification de modèle de MVC. Après avoir défini l'entité, vous pouvez la marquer là où la vérification est nécessaire. Pour l'attribut correspondant, vérifiez l'attribut IsValid du ModelState lorsque l'action démarre. Si la vérification échoue, la vue est renvoyée directement. Le frontal peut analyser et afficher la raison de l'échec de la vérification. L'API Web hérite également de cette fonctionnalité pratique, ce qui la rend plus pratique à utiliser :
public class CustomActionFilterAttribute : ActionFilterAttribute { public override void OnActionExecuting(HttpActionContext actionContext) { if (!actionContext.ModelState.IsValid) { actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, actionContext.ModelState); } } }
Ce filtre fournit la fonction de vérification du modèle. Si la vérification du modèle échoue, une erreur 400 sera renvoyée et passera pertinent. informations d’erreur à l’appelant. Son utilisation est la même que AuthFilterAttribute et peut être utilisée pour Action, Controller et globalement. Nous pouvons utiliser l'exemple suivant pour vérifier :
Le code est le suivant :
public class LoginEntity { [Required(ErrorMessage = "缺少用户名")] public string UserName { get; set; } [Required(ErrorMessage = "缺少密码")] public string Password { get; set; } }
[AllowAnonymous] [CustomActionFilter]public CreateResult PostLogin(LoginEntity entity) { //TODO:添加验证逻辑 return new CreateResult() {Id = "123456"}; }
Bien sûr, vous pouvez également analyser le ModelState en fonction de vos propres besoins et renvoyer les informations d'erreur à l'utilisateur via Request.CreateResponse() dans votre propre format.
J'utilise rarement la méthode OnActionExecuted dans le travail réel. Actuellement, elle n'a été utilisée que dans un scénario où les données de réponse partielle sont cryptées. La méthode d'utilisation est la même, lisez la réponse existante, cryptez-la puis donnez-la. Attribuez simplement la réponse chiffrée à actionContext.Response.
Je vais vous faire une démo :
public override async Task OnActionExecutedAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken) { var key = 10; var responseBody = await actionExecutedContext.Response.Content.ReadAsByteArrayAsync(); //以Byte数组方式读取Content中的数据 for (int i = 0; i < responseBody.Length; i++) { responseBody[i] = (byte)(responseBody[i] ^ key); //对每一个Byte做异或运算 } actionExecutedContext.Response.Content = new ByteArrayContent(responseBody); //将结果赋值给Response的Content actionExecutedContext.Response.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("Encrypt/Bytes"); //并修改Content-Type}
Grâce à cette méthode, nous effectuons une opération XOR sur chaque octet du contenu de la réponse. le contenu est simplement crypté. Vous pouvez utiliser un cryptage plus fiable en fonction de vos propres besoins, tel que AES, DES ou RSA... Grâce à cette méthode, vous pouvez traiter de manière flexible le résultat d'une action et répondre via un filtre. Le cryptage du contenu a une grande flexibilité. et polyvalence. Il peut obtenir de nombreuses informations sur l'action en cours, puis sélectionner la méthode de cryptage en fonction de ces informations, obtenir les paramètres requis pour le cryptage, etc. Si les paramètres utilisés pour le chiffrement ne dépendent pas de l'action actuellement exécutée, vous pouvez également utiliser HttpMessageHandler pour le traitement, que je présenterai dans un didacticiel ultérieur.
Le dernier filtre : ExceptionFilter
顾名思义,这个Filter是用来进行异常处理的,当业务发生未处理的异常,我们是不希望用户接收到黄页或者其他用户无法解析的信息的,我们可以使用ExceptionFilter来进行统一处理:
public class ExceptionFilter : ExceptionFilterAttribute { public override void OnException(HttpActionExecutedContext actionExecutedContext) { //如果截获异常为我们自定义,可以处理的异常则通过我们自己的规则处理 if (actionExecutedContext.Exception is DemoException) { //TODO:记录日志 actionExecutedContext.Response = actionExecutedContext.Request.CreateResponse( HttpStatusCode.BadRequest, new {Message = actionExecutedContext.Exception.Message}); } else { //如果截获异常是我没无法预料的异常,则将通用的返回信息返回给用户,避免泄露过多信息,也便于用户处理 //TODO:记录日志 actionExecutedContext.Response = actionExecutedContext.Request.CreateResponse(HttpStatusCode.InternalServerError, new {Message = "服务器被外星人拐跑了!"}); } } }
我们定义了一个ExceptoinFilter用于处理未捕获的异常,我们将异常分为两类:一类是我们可以预料的异常:如业务参数错误,越权等业务异常;还有一类是我们无法预料的异常:如数据库连接断开、内存溢出等异常。我们通过HTTP Code告知调用者以及用相对固定、友好的数据结构将异常信息告诉调用者,以便于调用者记录并处理这样的异常。
[CustomerExceptionFilter]public class TestController : ApiController { public int Get(int a, int b) { if (a < b) { throw new DemoException("A必须要比B大!"); } if (a == b) { throw new NotImplementedException(); } return a*b; } }
我们定义了一个Action:在不同的情况下会抛出不同的异常,其中一个异常是我们能够预料并认为是调用者传参出错的,一个是不能够处理的,我们看一下结果:
在这样的RestApi中,我们可以预先定义好异常的表现形式,让调用者可以方便地判断什么情况下是出现异常了,然后通过较为统一的异常信息返回方式让调用者方便地解析异常信息,形成统一方便的异常消息处理机制。
但是,ExceptionFilter只能在成功完成了Controller的初始化以后才能起到捕获、处理异常的作用,而在Controller初始化完成之前(例如在Controller的构造函数中出现了异常)则ExceptionFilter无能为力。对此WebApi引入了ExceptionLogger和ExceptionHandler处理机制,我们将在之后的文章中进行讲解。
二、Filter的执行顺序
在使用MVC的时候,ActionFilter提供了一个Order属性,用户可以根据这个属性控制Filter的调用顺序,而Web API却不再支持该属性。Web API的Filter有自己的一套调用顺序规则:
所有Filter根据注册位置的不同拥有三种作用域:Global、Controller、Action:
通过HttpConfiguration类实例下Filters.Add()方法注册的Filter(一般在App_Start\WebApiConfig.cs文件中的Register方法中设置)就属于Global作用域;
通过Controller上打的Attribute进行注册的Filter就属于Controller作用域;
通过Action上打的Attribute进行注册的Filter就属于Action作用域;
他们遵循了以下规则:
1、在同一作用域下,AuthorizationFilter最先执行,之后执行ActionFilter
2、对于AuthorizationFilter和ActionFilter.OnActionExcuting来说,如果一个请求的生命周期中有多个Filter的话,执行顺序都是Global->Controller->Action;
3、对于ActionFilter,OnActionExecuting总是先于OnActionExecuted执行;
4、对于ExceptionFilter和ActionFilter.OnActionExcuted而言执行顺序为Action->Controller->Global;
5、对于所有Filter来说,如果阻止了请求:即对Response进行了赋值,则后续的Filter不再执行。
关于默认情况下的Filter相关知识我们就讲这么一些,如果在文章中有任何不正确的地方或者疑问,欢迎大家为我指出。
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!