c# webapi 在swagger里添加全局过滤器

发布时间 2023-11-10 11:12:43作者: jevan

Swagger原理

  Swagger就是利用反射技术遍历所有Api接口,并且从xml文件中读取注释,在利用Swagger内置的模板组合html显示至客户端实现接口可视化,并且可调用。

在WEB Api中,引入了面向切面编程(AOP)的思想,在某些特定的位置可以插入特定的Filter进行过程拦截处理。引入了这一机制可以更好地践行DRY(Don’t Repeat Yourself)思想,通过Filter能统一地对一些通用逻辑进行处理,如:权限校验、参数加解密、参数校验等方面我们都可以利用这一特性进行统一处理,今天我们来介绍Filter的开发、使用以及讨论他们的执行顺序。

Filter的开发和调用

在默认的WebApi中,框架提供了三种Filter,他们的功能和运行条件如下表所示:

Filter 类型实现的接口描述
Authorization IAuthorizationFilter 最先运行的Filter,被用作请求权限校验
Action IActionFilter 在Action运行的前、后运行
Exception IExceptionFilter 当异常发生的时候运行

添加注册全局Filter的方法

1.创建一个ApiAuthorizationFilterAttribute.cs和ApiExceptionFilterAttribute.cs两个文件:

ApiAuthorizationFilterAttribute.cs文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class ApiAuthorizationFilterAttribute : AuthorizationFilterAttribute
{
    public override void OnAuthorization(HttpActionContext actionContext)
    {
 
        //如果用户方位的Action带有AllowAnonymousAttribute,则不进行授权验证
        if (actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any())
        {
            return;
        }
 
        var authorization = actionContext.Request.Headers.Authorization;
 
        if (authorization == null || authorization.Scheme != "Bearer")
        {
            actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized, new { status = "failed", message = "token不正确!!!" });
        }
        else
        {
            string username;
 
            var token = authorization.Parameter;
      //以下就是验证token的方法,可以自己写方法进行验证啦
            if (!ValidateToken(token, out username))
            {
                actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized, new { status = "failed", message = "token不正确!!!" });
            }
        }
    }
}

  ApiExceptionFilterAttribute.cs如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/// <summary>
/// 捕捉异常
/// </summary>
public class ApiExceptionFilterAttribute : ExceptionFilterAttribute
{
    /// <summary>
    /// 重写基类的异常处理方法
    /// </summary>
    /// <param name="context"></param>
    public override void OnException(HttpActionExecutedContext context)
    {
        //context.Exception.StackTrace
        //1.异常日志记录
        LogHelper.Error(context.Exception.ToString());
 
        //2.返回调用方具体的异常信息
        if (context.Exception is NotImplementedException)
        {
            context.Response = new HttpResponseMessage(HttpStatusCode.NotImplemented);
        }
        else if (context.Exception is TimeoutException)
        {
            context.Response = new HttpResponseMessage(HttpStatusCode.RequestTimeout);
        }
        else
        {
            //这里可以根据项目需要返回到客户端特定的状态码。如果找不到相应的异常,统一返回服务端错误500
            context.Response = new HttpResponseMessage(HttpStatusCode.InternalServerError);
        }
 
        base.OnException(context);
 
    }
 
    private JsonMediaTypeFormatter _JsonFormatter;
    private JsonMediaTypeFormatter JsonFormatter
    {
        get
        {
            if (_JsonFormatter == null)
            {
                _JsonFormatter = new JsonMediaTypeFormatter();
                _JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
            }
            return _JsonFormatter;
        }
    }
}

2.在WebApiConfig.cs文件中添加”注册全局Filter“的那两行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Web API 配置和服务
 
        // Web API 路由
        config.MapHttpAttributeRoutes();
 
        //注册全局Filter
        config.Filters.Add(new ApiAuthorizationFilterAttribute());
        config.Filters.Add(new ApiExceptionFilterAttribute());
 
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
 
        log4net.Config.XmlConfigurator.Configure();
 
    }
}

3.进行swagger的相关配置,新建一个HttpHeaderFilter.cs文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class HttpHeaderFilter : IOperationFilter
{
    public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
    {
        if (operation.parameters == null)
        {
            operation.parameters = new List<Parameter>();
        }
 
        var filterPipeline = apiDescription.ActionDescriptor.GetFilterPipeline(); //判断是否添加权限过滤器
        var isAuthorized = filterPipeline.Select(filterInfo => filterInfo.Instance).Any(filter => filter is ApiAuthorizationFilterAttribute); //判断是否需要经过验证
        var allowAnonymous = apiDescription.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any();//判断是否否允许匿名方法
        if (isAuthorized && !allowAnonymous)
        {
            operation.parameters.Add(new Parameter { name = "Authorization", @in "header", description = "Token", required = false, type = "string" });
        }
    }
}

4.在文件SwaggerConfig.cs文件中找到Register方法,GlobalConfiguration.Configuration.EnableSwagger中添加:

1
c.OperationFilter<HttpHeaderFilter>();

  大功告成,如下图: