WEB Api에서는 AOP(관점 지향 프로그래밍) 개념이 도입되었으며, 프로세스 차단 처리를 위해 특정 위치에 특정 필터를 삽입할 수 있습니다. 이 메커니즘을 도입하면 DRY(Don't Repeat Yourself) 아이디어를 더 잘 구현할 수 있습니다. 필터를 통해 권한 확인, 매개변수 암호화 및 암호 해독, 매개변수 확인 등과 같은 일부 공통 논리를 균일하게 처리할 수 있습니다. 오늘은 Filter의 개발과 사용법을 소개하고 실행 순서에 대해 논의하겠습니다.
1. Filter 개발 및 호출
프레임워크에서는 기본 WebApi에서 세 가지 유형의 Filter를 제공하며, 해당 기능과 동작 조건은 다음 표와 같습니다. :
필터 Filter 类型 实现的接口 描述 Authorization IAuthorizationFilter 最先运行的Filter,被用作请求权限校验 Action IActionFilter 在Action运行的前、后运行 Exception IExceptionFilter 当异常发生的时候运行 |
구현된 인터페이스 |
설명 |
||||||||||||
승인 | IAuthorizationFilter | 첫 번째로 실행할 항목필터, 권한 확인 요청에 사용 | tr>||||||||||||
액션 | IActionFilter | In액션작업 전후 | ||||||||||||
예외 | IExceptionFilter | 예외 발생 시 실행 |
먼저 간단한 권한 제어에 사용할 수 있는 AuthorizatoinFilter를 구현합니다.
(actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute> verifyResult = actionContext.Request.Headers.Authorization!= && == ; (!= HttpError(
사용자 인증을 위한 간단한 필터가 개발되었습니다. 이 필터에는 Authorization 헤더와 매개변수가 포함되어야 합니다. 123456. 통과하면 해제됩니다. 통과하지 못하면 401 오류가 반환되고 콘텐츠에 토큰이 잘못되었다는 메시지가 표시됩니다. 다음으로, 이 필터를 등록해야 합니다. 필터를 등록하는 세 가지 방법이 있습니다.
첫 번째 방법: 권한을 제어하려는 작업에 AuthFilterAttribute를 추가합니다.
public class PersonController : ApiController { [AuthFilter] public CreateResult Post(CreateUser user) { return new CreateResult() {Id = "123"}; } }
이 방법은 다음과 같습니다. 단일 작업 권한 제어에 적합합니다.
두 번째 방법은 해당 컨트롤러를 찾아 다음 속성을 추가하는 것입니다:
[AuthFilter] public class PersonController : ApiController { public CreateResult Post(CreateUser user) { return new CreateResult() {Id = "123"}; } }
이 방법은 전체 컨트롤러를 제어하는 데 적합합니다. 이 속성을 추가하면 전체 컨트롤러의 모든 작업에 권한 제어.
세 번째 방법은 App_StartWebApiConfig.cs를 찾아 Register 메서드 아래에 필터 인스턴스를 추가하는 것입니다.
{ id =
이 방법은 모든 API를 제어하는 데 적합하며 모든 작업은 이 권한 제어를 허용합니다. .
대부분의 경우 각 API의 권한 확인 로직은 동일합니다. 이러한 전제하에 필터의 전역 등록을 사용하는 것이 가장 간단하고 편리한 방법입니다. 그러나 확실한 문제가 있습니다. users API에 제어(예: 로그인)가 필요하지 않으면 어떻게 해야 합니까? 다음과 같은 API에서 이 작업을 수행할 수 있습니다.
[AllowAnonymous]public CreateResult PostLogin(LoginEntity entity) { //TODO:添加验证逻辑 return new CreateResult() {Id = "123456"}; }
AllowAnonymousAttribute로 작업을 표시했는데 확인 로직에서 권한 확인을 수행하지 않고 API를 무시했습니다.
실제 개발에서는 세션과 유사한 메커니즘을 설계하여 사용자 로그인을 통해 토큰을 얻고, Authorization 헤더를 추가하고 후속 대화형 HTTP 요청에서 이 토큰을 가져오고, AuthFilterAttribute에서 토큰을 확인하기 위해 사용자 정의할 수 있습니다. 표준 토큰 검증 프로세스를 구현할 수 있습니다.
다음으로 ActionFilter를 소개합니다.
ActionFilterAttrubute는 차단을 위한 두 가지 방법인 OnActionExecuting과 OnActionExecuted를 제공하며, 둘 다 동기식 및 비동기식 방법을 제공합니다.
OnActionExecuting 메서드는 Action이 실행되기 전에 실행되고, OnActionExecuted 메서드는 Action이 실행된 후에 실행됩니다.
응용 시나리오를 살펴보겠습니다. MVC를 사용해 본 학생들은 MVC의 모델 바인딩 및 모델 검증에 익숙해야 합니다. Entity를 정의한 후 검증이 필요한 곳에 표시하면 됩니다. 해당 Attribute에 대해서는 Action 시작 시 ModelState의 IsValid 속성을 확인합니다. 확인에 실패하면 프런트 엔드에서 확인 실패 이유를 구문 분석하고 표시할 수 있습니다. Web API도 이 편리한 기능을 계승하여 사용이 더욱 편리해졌습니다.
public class CustomActionFilterAttribute : ActionFilterAttribute { public override void OnActionExecuting(HttpActionContext actionContext) { if (!actionContext.ModelState.IsValid) { actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, actionContext.ModelState); } } }
이 필터는 모델 검증을 통과하지 못한 경우 400 오류를 반환하고 관련 항목을 반환합니다. 호출자에게 오류 메시지가 표시됩니다. 사용법은 AuthFilterAttribute와 동일하며 Action, Controller 및 전역적으로 사용할 수 있습니다. 다음 예를 사용하여 확인할 수 있습니다.
코드는 다음과 같습니다.
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"}; }
물론, ModelState를 구문 분석한 다음 Request.CreateResponse()를 통해 사용자에게 고유한 형식으로 오류 메시지를 반환해야 합니다.
실제 업무에서는 OnActionExecuted 방식을 거의 사용하지 않고 있으며, 현재는 부분 응답 데이터를 암호화하는 경우에만 사용하고 있으며, 기존 응답을 읽어서 암호화한 후 전달합니다. 암호화된 응답을 actionContext.Response에 할당하기만 하면 됩니다.
데모를 드립니다:
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}
이 방법을 통해 응답 Content의 각 Byte에 대해 XOR 연산을 수행하고, XOR을 수행합니다. 응답 내용에 대한 연산 간단한 암호화 이후 필요에 따라 AES, DES, RSA 등 보다 안정적인 암호화를 수행할 수 있습니다. 이 방법을 통해 Action의 결과를 유연하게 처리하고 응답 내용을 암호화할 수 있습니다. Filter를 통해 현재 Action에 대한 많은 정보를 얻을 수 있으며, 이 정보를 기반으로 암호화 방법을 선택하고 암호화에 필요한 매개변수를 얻을 수 있습니다. 암호화에 사용되는 매개변수가 현재 실행되는 작업에 종속되지 않는 경우 처리를 위해 HttpMessageHandler를 사용할 수도 있습니다. 이에 대해서는 후속 자습서에서 소개하겠습니다.
마지막 필터: 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相关知识我们就讲这么一些,如果在文章中有任何不正确的地方或者疑问,欢迎大家为我指出。
위 내용은 Asp.Net WebAPI(컬렉션)에서 Filter의 사용 및 실행 순서의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!