聊一聊Asp.net过滤器Filter那一些事

2020-06-09 12:59:55王旭

MVC和API异同:

  命名空间:MVC:System.Web.Http.Filters;API:System.Web.Mvc

  注入方式:在注入方式上,主要包括:全局->控制器Controller->行为Action

  全局注册:针对所有系统的所有Aciton都使用

  Controller:只针对该Controller下的Action起作用

  Action:只针对该Action起作用

其中全局注册,针对MVC和API还有一些差异:

  MVC在 FilterConfig.cs中注入

filters.Add(new XYHMVCAuthorizeAttribute());

     API 在 WebApiConfig.cs 中注入

config.Filters.Add(new XYHAPIAuthorizeAttribute());

  注意事项:在实际使用中,针对认证授权,我们一般都是添加全局认证,但是,有的action又不需要做认证,比如本来的登录Action等等,那么该如何排除呢?其实也很简单,我们只需要在自定定义一个Attribute集成Attribute,或者系统的AllowAnonymousAttribute,在不需要验证的action中只需要注册上对于的Attribute,并在验证前做一个过滤即可,比如:

// 有 AllowAnonymous 属性的接口直接开绿灯
   if (actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any())
   {
    return;
   }

API AuthFilterAttribute实例代码

/// <summary>
 /// 授权认证过滤器
 /// </summary>
 public class XYHAPIAuthFilterAttribute : AuthorizationFilterAttribute
 {
  /// <summary>
  /// 认证授权验证
  /// </summary>
  /// <param name="actionContext">请求上下文</param>
  public override void OnAuthorization(HttpActionContext actionContext)
  {
   // 有 AllowAnonymous 属性的接口直接开绿灯
   if (actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any())
   {
    return;
   }

   // 在请求前做一层拦截,主要验证token的有效性和验签
   HttpRequest httpRequest = HttpContext.Current.Request;

   // 获取apikey
   var apikey = httpRequest.QueryString["apikey"];

   // 首先做IP白名单校验 
   MBaseResult<string> result = new AuthCheckService().CheckIpWhitelist(FilterAttributeHelp.GetIPAddress(actionContext.Request), apikey);

   // 检验时间搓
   string timestamp = httpRequest.QueryString["Timestamp"];
   if (result.Code == MResultCodeEnum.successCode)
   {
    // 检验时间搓 
    result = new AuthCheckService().CheckTimestamp(timestamp);
   }

   if (result.Code == MResultCodeEnum.successCode)
   {
    // 做请求频率验证 
    string acitonName = actionContext.ActionDescriptor.ActionName;
    string controllerName = actionContext.ActionDescriptor.ControllerDescriptor.ControllerName;
    result = new AuthCheckService().CheckRequestFrequency(apikey, $"api/{controllerName.ToLower()}/{acitonName.ToLower()}");
   }

   if (result.Code == MResultCodeEnum.successCode)
   {
    // 签名校验

    // 获取全部的请求参数
    Dictionary<string, string> queryParameters = httpRequest.GetAllQueryParameters();

    result = new AuthCheckService().SignCheck(queryParameters, apikey);

    if (result.Code == MResultCodeEnum.successCode)
    {
     // 如果有NoChekokenFilterAttribute 标签 那么直接不做token认证
     if (actionContext.ActionDescriptor.GetCustomAttributes<XYHAPINoChekokenFilterAttribute>().Any())
     {
      return;
     }

     // 校验token的有效性
     // 获取一个 token
     string token = httpRequest.Headers.GetValues("Token") == null ? string.Empty :
      httpRequest.Headers.GetValues("Token")[0];

     result = new AuthCheckService().CheckToken(token, apikey, httpRequest.FilePath);
    }
   }

   // 输出
   if (result.Code != MResultCodeEnum.successCode)
   {
    // 一定要实例化一个response,是否最终还是会执行action中的代码
    actionContext.Response = new HttpResponseMessage(HttpStatusCode.OK);
    //需要自己指定输出内容和类型
    HttpContext.Current.Response.ContentType = "text/html;charset=utf-8";
    HttpContext.Current.Response.Write(JsonConvert.SerializeObject(result));
    HttpContext.Current.Response.End(); // 此处结束响应,就不会走路由系统
   }
  }
 }