WebApi详解+Unity注入--中篇:.net core的WebAPI

8,RESTful风格

8.1,什么是RESTful?

REST全称是Representational State Transfer,中文意思是表述性状态转移。

REST本身并没有创造新的技术、组件或服务

REST指的是一组架构约束条件和原则,如果一个架构符合REST的约束条件和原则,我们就称他为RESTfull架构。

理论上REST架构风格并不是绑定在Http上,只不过目前Http是唯一与REST相关的实例。所以我们这里描述的REST也是通过Http实现REST.

8.2,REST主要规则是什么?
8.2.1,资源与URL,所有的资源都有一个资源标志符

Core webApi 访问一块资源

复制代码
https://loaclhost:8000/Company    ---代表Company的一块资源
https://localhost:8000/User      ---代表User的一块资源
8.2.2,同一资源接口
html 复制代码
冥等性:对同一个Rest接口的多次访问,得到的资源状态时相同的。
安全性:对该REST接口访问,不会是服务器端资源的状态发生改变。
8.2.3,资源的表述

服务端可以通过Content-Type告诉客户端资源的表述形式。

资源的表述形式有xml,html,json等格式,图片可以使用PNG,Jpeg展现出来

8.2.4,资源的链接

在设计RESTfull架构时,使用很多时间来寻找漂亮的URI,而忽略了超媒体。所以,应给多花一些时间来给资源的表述提供链接,而不是专注于资源的CURD

8.2.5,状态的转移

原则上要求无状态通信原则

9,Core WebApi返回结果中文转义问题

设置json序列化中支持的编码器解决返回结果中文转义问题

C# 复制代码
 public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            //设置序列化的编码器,解决编码转义问题
            services.AddControllers().AddJsonOptions(jsonOption=> {
                jsonOption.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(System.Text.Unicode.UnicodeRanges.All);
            })
                ;
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "WebAPICore应用", Version = "v1" });
            });
        }
     }

10,Swagger配置

作用: 根据ControllerAction自动生成OpenAPI风格的文档,该文档支持多版本文档的切换查阅。

10.1 安装Swagger

一般情况在创建WebApiCore项目时选择OpenApi支持选项,选择该选项后创建项目时自动安装该Nuget

10.2 配置Swagger

配置均是在StartUp.cs文件进行

10.2.1,解决编码转义问题
C# 复制代码
public void ConfigureServices(IServiceCollection services)
      {
          //解决编码转义问题
          services.AddControllers().AddJsonOptions(jsonOption=> {
              jsonOption.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(System.Text.Unicode.UnicodeRanges.All);
          })
}
10.2.2,版本控制(忽略这个,直接查阅第12节版本控制)
C# 复制代码
 public void ConfigureServices(IServiceCollection services)
        {
            //解决编码转义问题
            services.AddControllers().AddJsonOptions(jsonOption=> {
                jsonOption.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(System.Text.Unicode.UnicodeRanges.All);
            })
                ;
            //若要启用Swagger的版本控制需要在api控制器或者方法上添加特性[ApiExplorerSettings(GroupName="版本号"]
            //1,生成不同版本的json文档
            #region 分版本Swagger配置1
            Enum.GetNames(typeof(Utility.Swagger.ApiVersions)).ToList().ForEach(version =>
            {
                services.AddSwaggerGen(c =>
                {
                    c.SwaggerDoc(version, new OpenApiInfo
                    {
                        Title = $"枫林OpenAPI {version}",
                        Version = "v1",
                        Description = $"通用版本的CoreApi版本{version}"
                    });
                });
               
            });
     }
C# 复制代码
  public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseSwagger();
                //2,SwaggerUI使用不同版本的Swagger json文件
                #region 分版本的Swagger配置2
                app.UseSwaggerUI(c =>
                {
                    Enum.GetNames(typeof(Utility.Swagger.ApiVersions)).ToList().ForEach(version =>
                        c.SwaggerEndpoint($"/swagger/{version}/swagger.json", $"WebAPICore应用 {version}"));
                });
                #endregion
            }
            app.UseRouting();
            app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }

添加Swagger版本控制特性([ApiExplorerSettings])的控制器

C# 复制代码
 [ApiController]
    [Route("[controller]")]
//在Swagger版本1中呈现
    [ApiExplorerSettings(GroupName =nameof(Utility.Swagger.ApiVersions.V1),IgnoreApi =false)]
    public class WeatherForecastController : ControllerBase
    {
       
    }
10.2.3,配置Swagger显示注释

1,在项目属性中设置输出xml文档文件

2,配置展示注释

C# 复制代码
  #region 配置展示注释
            services.AddSwaggerGen(option =>
            {
                //注释路径位置
                var xmlfile = System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.FullyQualifiedName;
                string commentfile = xmlfile.Substring(0, xmlfile.LastIndexOf('.')) + ".xml";
                option.IncludeXmlComments(commentfile, true);
                //对action的名称进行排序,如果有多个,就可以看见效果
                option.OrderActionsBy(apiDesciotion => apiDesciotion.RelativePath);
            });
            #endregion
10.2.4,Token传递

添加访问认证Token要求

C# 复制代码
  #region 扩展传入token
                //添加安全定义
                option.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
                {
                    Description = "请输入token,格式为 Bearer **** (注意中间必须是空格)",
                    Name = "Authorization",
                    In = ParameterLocation.Header,
                    BearerFormat = "JWT",
                    Scheme = "Bearer"
                });
                //添加安全要求
                option.AddSecurityRequirement(new OpenApiSecurityRequirement
                {
                    {
                        new OpenApiSecurityScheme
                        {
                          Reference=new OpenApiReference
                             {
                              Type= ReferenceType.SecurityScheme,
                               Id="Bearer"
                             }
                        },new List<string>() }

                });
 #endregion
10.2.5,扩展文件上传按钮
C# 复制代码
 #region 扩展文件上传,展示文件上传按钮
                option.OperationFilter<Utility.Swagger.FileUploadFilter>();
                #endregion
C# 复制代码
public class FileUploadFilter : IOperationFilter
    {
        /// <summary>
        /// 扩展文件上传,展示文件上传按钮
        /// </summary>
        /// <param name="operation"></param>
        /// <param name="context"></param>
        public void Apply(OpenApiOperation operation, OperationFilterContext context)
        {
            const string FileUploadContentType = "multipart/form-data";
            if (operation.RequestBody == null || !operation.RequestBody.Content.Any(
                x => x.Key.Equals(FileUploadContentType, StringComparison.InvariantCultureIgnoreCase)))
            {
                return;
            }
            //只有Action的形参类型为IFormCollection才展示按钮
            if (context.ApiDescription.ParameterDescriptions[0].Type == typeof(IFormCollection))
            {
                operation.RequestBody = new OpenApiRequestBody
                {
                    Description = "文件上传",
                    Content = new Dictionary<string, OpenApiMediaType>
                    {
                        { FileUploadContentType,new OpenApiMediaType
                        {
                             Schema=new OpenApiSchema
                             {
                                  Type="object",
                                  Required=new HashSet<string>{"file"},
                                   Properties=new Dictionary<string, OpenApiSchema>
                                   {
                                       {"file",new OpenApiSchema{Type="string",Format="binary"} }
                                   }
                             }
                        }
                        }
                    }
                };
            }
        }
    }

11,全局路由扩展

添加全局路由前缀

C# 复制代码
 public void ConfigureServices(IServiceCollection services)
        {
            //配置路由前缀
            services.AddControllers(option =>
            {
                option.Conventions.Insert(0, new Utility.Route.RouteConvention(new RouteAttribute("api/")));
            });
           //配置Swagger
            services.AddSwaggerGenExt();

        }
C# 复制代码
 /// <summary>
    /// 全局路由前缀配置
    /// </summary>
    public class RouteConvention : IApplicationModelConvention
    {
        /// <summary>
        /// 定义一个路由前缀变量
        /// </summary>
        readonly AttributeRouteModel _centralPrefix;
       /// <summary>
       /// 调用时传入指定的路由前缀
       /// </summary>
       /// <param name="routeTemplateProvider"></param>
        public RouteConvention(IRouteTemplateProvider routeTemplateProvider)
        {
            _centralPrefix = new AttributeRouteModel(routeTemplateProvider);
        }
        public void Apply(ApplicationModel application)
        {
            foreach (var controller in application.Controllers)
            {
                //1,已经标记了RouteAttribute的Controller
                foreach (var selectorModel in controller.Selectors.Where(item=>item.AttributeRouteModel!=null))
                {
                    //在当前路由上再添加一个路由前缀
                    selectorModel.AttributeRouteModel = AttributeRouteModel.CombineAttributeRouteModel(_centralPrefix, selectorModel.AttributeRouteModel);
                }
                //2,没有标记RouteAttribute的Controller

                foreach (var unSelectorModel in controller.Selectors.Where(item => item.AttributeRouteModel != null))
                {
                    //在当前路由上再添加一个路由前缀
                    unSelectorModel.AttributeRouteModel = _centralPrefix;
                }
            }
        }
    }

12,版本控制

复制代码
Nuget:
Microsoft.AspNetCore.Mvc.Versioning
Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer
C# 复制代码
 public void ConfigureServices(IServiceCollection services)
        {

            //配置路由前缀
            //services.AddControllers(option =>
            //{
            //    option.Conventions.Insert(0, new Utility.Route.RouteConvention(new RouteAttribute("api/")));
            //});
            //配置Swagger
            services.AddSwaggerGenExt();
            //配置Swagger多版本控制
            services.AddSwaggerGenWithVersioning(Enum.GetNames(typeof(Utility.Swagger.ApiVersions)));

        }
C# 复制代码
  /// <summary>
        /// 控制swagger多版本生成
        /// </summary>
        /// <param name="services"></param>
        /// <param name="apiVersions"></param>
        public static void AddSwaggerGenWithVersioning(this IServiceCollection services, string[] apiVersions)
        {
            services.AddSwaggerGen(m =>
            {
                // 注册每个版本
                foreach (var version in apiVersions)
                {
                    m.SwaggerDoc(version, new OpenApiInfo
                    {
                        Title = $"枫林 API {version.ToUpper()}",
                        Version = version
                    });
                }
                // 冲突处理
                m.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());
                // 根据控制器上的 ApiVersionAttribute 筛选文档
                m.DocInclusionPredicate((docName, apiDesc) =>
                {
                    if (!apiDesc.TryGetMethodInfo(out var methodInfo)) return false;
                    var versions = methodInfo.DeclaringType?
                        .GetCustomAttributes(true)
                        .OfType<ApiVersionAttribute>()
                        .SelectMany(attr => attr.Versions)
                        .Select(v => $"v{v.MajorVersion}")
                        .ToList();
                    return versions?.Contains(docName) ?? false;
                });
            });
            // 配置 API 版本控制
            services.AddApiVersioning(options =>
            {
                options.DefaultApiVersion = new ApiVersion(1, 0); // 默认版本为 1.0
                options.AssumeDefaultVersionWhenUnspecified = true; // 未指定版本时使用默认版本
                options.ReportApiVersions = true; // 返回支持的版本信息
                options.ApiVersionReader = ApiVersionReader.Combine(
                    new QueryStringApiVersionReader("version"), // 从查询字符串读取版本号
                    new UrlSegmentApiVersionReader(), // 从 URL 路径读取版本号
                    new HeaderApiVersionReader("X-API-Version"), // 从请求头读取版本号
                    new MediaTypeApiVersionReader("version") // 从媒体类型读取版本号
                );
            });
        }
C# 复制代码
namespace WebAPICore应用.Controllers.v1
{
    //[Route("api/[controller]")]
    [ApiController]
    [ApiVersion("1.0")]//指明版本
    [Route("api/v{version:apiVersion}/[controller]")]
    //控制器上添加swagger的
    // [ApiExplorerSettings(IgnoreApi =false,GroupName =nameof(Utility.Swagger.ApiVersions.V1))]
    public class UserController : ControllerBase
    {
        // GET: api/<UserController>
        [HttpGet]
        public IEnumerable<string> Get()
        {
            return new string[] { "V1版本", "V1版本" };
        }
    }
}
C# 复制代码
namespace WebAPICore应用.Controllers.v2
{
    //[Route("api/[controller]")]
    [ApiController]
    // [ApiExplorerSettings(IgnoreApi = false, GroupName = nameof(Utility.Swagger.ApiVersions.V2))]
    [ApiVersion("2.0")]//指明版本
    [Route("api/v{version:apiVersion}/[controller]")]
    public class UserController : ControllerBase
    {
        // GET: api/<UserController>
        [HttpGet]
        public IEnumerable<string> Get()
        {
            return new string[] { "V2版本", "V2版本" };
        }
    }
}

13,API参数特性修饰

13.1,FromServices
  1. 表示来自于IOC容器创建。
  2. 必然需要在IOC容器先注册
  3. 如果没有标记[FromServices],则默认这个参数需要通过调用方传递。
13.2,FromBody

搜集来自于客户端请求的参数中来自于Body的数据。

13.3,FromForm

搜集来自于客户端Form表单中的参数。

13.4,FromHeader

搜集来自于客户端请求的Header参数数据。

13.5,FromQuery

搜集来自客户端请求的查询字符串参数数据。

13.6,FromRoute

在来自客户端请求的路由中去收集这个参数的数据

14,日志记录

14.1,log4net日志记录

支持文本日志,数据库日志

  1. Nuget引入程序包log4net+Microsoft.Extensions.Logging.Log4Net.AspNetCore

  2. 准备配置文件【设置为始终复制】

  3. 植入log4net

    C# 复制代码
    builder.Logging.AddLog4Net("log4net.config");
  4. 注入log对象,写日志。

15,AOP面向切面编程

15.1,什么是AOP?

AOP(Aspect orient Programming),面向切面编程,作为面向对象编程的一种补充,可以在不破坏之前的封装为基础动态增加一些功能,从而让系统更具可扩展性。

15.2,Core WebApi中的AOP支持有哪些?
  • 授权------Authorize
  • 资源------Resource
  • 异常------Exception
  • 方法前后------Action
  • AlwayRunResult
  • 结果前后------Result
15.3,如何使用带有注入参数的Fillter

**使用[ServiceFilter]或者[TypeFilter]**为方法或者类引入带有注入参数Fillter特性。实际上测试发现使用[ServiceFilter]抛异常提示需要注册,而[TypeFiler]正常。

15.3,IResourceFilter扩展定制
  • 定义类,实现IResourceFilter/IAsyncRessourceFilter接口,继承Attribute

  • 实现方法

  • 标记在Api方法上

  • 执行时机:API方法执行前与执行后

  • 适用场景:为缓存而生。缓存:历史存储区域,以key-value格式保存数据。

C# 复制代码
/// <summary>
    /// 扩展缓存
    /// </summary>
    public class CustomCacheResourceFilterAttribute : Attribute, IResourceFilter
    {
        //定义一个缓存字典
        static Dictionary<string, object> cacheDictionary = new Dictionary<string, object>();
        //顺序:A
        /// <summary>
        /// api执行后执行
        /// </summary>
        /// <param name="context"></param>
        public void OnResourceExecuted(ResourceExecutedContext context)
        {
            //api 执行完成后缓存请求url
            string requestPath = context.HttpContext.Request.Path;
            cacheDictionary[requestPath] = context.Result;
        }
       //顺序:B
        /// <summary>
        /// api执行前执行
        /// </summary>
        /// <param name="context"></param>
        public void OnResourceExecuting(ResourceExecutingContext context)
        {
            //查询是否已经存储过该请求
            string requestPath = context.HttpContext.Request.Path;//Url地址
            if (cacheDictionary.ContainsKey(requestPath))
            {
                //如果包含则获取键值后直接返回不再执行后面的api方法,
                //如果Result==null,则继续执行后面的api方法
                context.Result = cacheDictionary[requestPath] as IActionResult;
            }

        }
    }
C# 复制代码
   //顺序:C
[HttpGet("{id}")]
        [Utility.Filters.CustomCacheResourceFilter]//扩展缓存功能
        public IActionResult Get(int id)
        {
            return new JsonResult(new { 
                Id=id,
                Method=nameof(Get),
                DataTime=DateTime.Now
            });
        }

执行顺序为:B->构造方法->C->A

第一次请求

第二次请求

因为获取的是上次的缓存所以结果一模一样。

15.4,IActionFilter扩展定制
  • 定义类,实现IActionFilter/IAsyncActionFilter接口,继承Attribute

  • 实现方法

  • 标记在Api方法上

  • 执行时机:API方法执行前与执行后

  • 特点

    • 与ResourceFilter相比
      • ResourceFilter使用连个方法包裹了控制器的构造方法+Api
      • ActionFilter使用连个办法只包裹了API逻辑部分。
  • ActionFilter场景使用:

    • 可以扩展为缓存,但是相对而言ResourceFilter性能更高些,请求处理的环节更少
    • ActionFillter更靠近api所以一般用于扩展日志功能

ResourceFilter流程图 (以上文自定义的CustomCacheResourceFilterAttribute为例)
客户端缓存存在
缓存不存在
客户端请求
OnResourceExecuting
获取缓存值
取缓存值推送至客户端
执行控制器构造方法
执行API方法
结果推送至客户端
执行OnResourceExecuted保存此次结果用于缓存

ActionFilter流程图
缓存值存在
缓存不存在
客户端请求
执行控制器构造方法
OnActionExecuting
取缓存值返回至客户端
执行API方法
结果推送至客户端
执行OnResourceExecuted保存此次结果用于缓存

ResourceFilter在缓存存在时不用调用控制器构造方法,而ActionFilter不管缓存存不存在每次都需要调用构造方法。所以在缓存方面ResourceFilter性能优于ActionFilter

实现IActionFilter的自定义类

C# 复制代码
 public class CustomLogActionFilterAttribute : Attribute, IActionFilter
    {
        log4net.ILog logger;
        public CustomLogActionFilterAttribute(log4net.ILog logger)
        {
            this.logger = logger;
        }
        public void OnActionExecuted(ActionExecutedContext context)
        {
            string controllerName = context.HttpContext.Request.RouteValues["controller"]?.ToString();
            string methodName = context.ActionDescriptor.RouteValues["action"];
            logger.Info($"访问{controllerName}.{methodName}执行OnActionExecuted");
        }

        public void OnActionExecuting(ActionExecutingContext context)
        {

            string controllerName = context.HttpContext.Request.RouteValues["controller"]?.ToString();
            string methodName = context.HttpContext.Request.RouteValues["action"]?.ToString();
            
            logger.Info($"访问{controllerName}.{methodName}执行OnActionExecuting");
        }
    }
C# 复制代码
 [HttpGet]
        //[Utility.Filters.CustomCacheResourceFilter]//扩展缓存功能
        [TypeFilter(typeof(Utility.Filters.CustomLogActionFilterAttribute))]
//使用ServicceFilter需要注册否则抛异常
      // [ServiceFilter(typeof(Utility.Filters.CustomLogActionFilterAttribute))]
        public IEnumerable<string> Get()
        {
            logger.Info($"访问{nameof(FiltersController)}.{nameof(Get)}");
            return new string[] { "value1", "value2" };
        }
text 复制代码
2025-12-29 21:16:51,025 [4] INFO  loggerAppender [29] - 访问Filters.Get执行OnActionExecuting 
2025-12-29 21:16:53,130 [4] INFO  loggerAppender [30] - 访问FiltersController.Get 
2025-12-29 21:17:14,546 [4] INFO  loggerAppender [20] - 访问Filters.Get执行OnActionExecuted 
15.5,IExceptionFilter扩展定制
C# 复制代码
 public class CustomExceptionFilterAttribute : Attribute, IExceptionFilter
    {
        public void OnException(ExceptionContext context)
        {
            if (!context.ExceptionHandled)
            {
                context.Result = new JsonResult(new
                {
                    success=false,
                    msg=context.Exception.Message,
                   
                });
                context.ExceptionHandled = true;
            }
        }
    }
C# 复制代码
 [HttpGet("Calculate/{val}")]
        [Utility.Filters.CustomExceptionFilter]
        public double Calculate(int val)
        {
            return 12 / val;
        }

正常时:

异常时:以自定义的形式向客户端推送信息。

15.6,IAsyncAuthorizationFilter鉴权实现整个过程

引入NuGet包:Microsoft.IdentityModel.JsonWebTokens

C# 复制代码
 public class AppCredential
    {
       
        public string ClientId { get; set; }
        public string Secret { get; set; }
    }
 public class Application
    {
        public int ApplicationId { get; set; }
        public string ApplicationName { get; set; }
        public string ClientId { get; set; }
        public string Secret { get; set; }
        public string Scopes { get; set; }
    }
 public class AppRepository
    {
        static List<Application> _applications = new List<Application>
        {
            new Application
            {
                ApplicationId=1,
                ApplicationName="webapi",
                ClientId="aa-bb-cc",
                Secret="893F4720-F3E5-46A4-BBE9-B3B2BB6E0F2E",
                Scopes="read,write"
            }
        };
        public static bool Authenticate(string ClientId, string Secret)
        {
            return _applications.Exists(application =>
            {
                return application.ClientId.Equals(ClientId, StringComparison.OrdinalIgnoreCase) && application.Secret.Equals(Secret, StringComparison.OrdinalIgnoreCase);
            });
        }
        public static Application GetApplicationByClientId(string clientId)
        {
            return _applications.FirstOrDefault(app => app.ClientId.Equals(clientId, StringComparison.OrdinalIgnoreCase));
        }
    }
C# 复制代码
public class Authenticator
    {
        public static string CreateToken(string clientId, DateTime expiresAt, string strSecurityKey)
        {
            //包含三部分 header,payload,Signature
            //Algorithm:算法。秘钥+算法
            //Sha256的SecurityKey的长度需要是'256'个 bit,即32个byte
            //所以为兼容所有秘钥长度这里转换为md5
            string securityKey = string.Empty;
            using (var md5 = MD5.Create())
            {
                //md5计算结果为16个byte
                byte[] keyBytes = md5.ComputeHash(System.Text.Encoding.UTF8.GetBytes(strSecurityKey));
                securityKey = keyBytes.Select(b => b.ToString("X2")).Aggregate((a, b) => a + b);
            }
            var signingCredentials = new SigningCredentials(
                 new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes(securityKey)),
                SecurityAlgorithms.HmacSha256Signature
                );
            //Payload(Claims)
            Application app = AppRepository.GetApplicationByClientId(clientId);
            var claimsDictionary = new Dictionary<string, object>
            {
                {"AppName",app.ApplicationName },
                {"Read",app.Scopes?.Contains("read",StringComparison.OrdinalIgnoreCase) },
                {"Write",app.Scopes?.Contains("write",StringComparison.OrdinalIgnoreCase) }
            };
            var tokenDescriptior = new SecurityTokenDescriptor
            {
                SigningCredentials = signingCredentials,
                Claims = claimsDictionary,//负载
                Expires = expiresAt,//过期时间
                NotBefore = DateTime.UtcNow//不能早于这个时间
            };
            var tokenHandler = new JsonWebTokenHandler();
            return tokenHandler.CreateToken(tokenDescriptior);
        }
        public static async Task<bool> VerifyTokenAsync(string tokenString, string securityKey)
        {
            if (string.IsNullOrEmpty(tokenString) || string.IsNullOrEmpty(securityKey))
            {
                return false;
            }
            string strSecurityKey = string.Empty;
            using (var md5 = MD5.Create())
            {
                //md5计算结果为16个byte
                byte[] keyBytes = md5.ComputeHash(System.Text.Encoding.UTF8.GetBytes(securityKey));
                strSecurityKey = keyBytes.Select(b => b.ToString("X2")).Aggregate((a, b) => a + b);
            }
            var keyByetes = System.Text.Encoding.UTF8.GetBytes(strSecurityKey);
            var tokenHander = new JsonWebTokenHandler();
            var validationParameters = new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(keyByetes),
                ValidateIssuer = false,
                ValidateAudience = false,
                ValidateLifetime = true,//验证有效期
                ClockSkew = TimeSpan.Zero//时钟偏差量
            };
            try
            {
                var result = await tokenHander.ValidateTokenAsync(tokenString, validationParameters);
                return result.IsValid;
            }
            catch (SecurityTokenMalformedException)
            {
                return false;
            }
            catch (SecurityTokenExpiredException)
            {
                return false;
            }
            catch (SecurityTokenInvalidSignatureException)
            {
                return false;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
    }
C# 复制代码
 public class JwtTokenAuthFilterAttribute : Attribute, IAsyncAuthorizationFilter
    {
        public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
        {
            //1,Get Authorization header from the request
           if(!context.HttpContext.Request.Headers.TryGetValue("Authorization",out var authorizationHeader))
            {
                context.Result = new UnauthorizedResult();
                return;
            }
           //2,Get rid of the Bearer prefix
            string tokenString = authorizationHeader;
            if (tokenString.StartsWith("Bearer", StringComparison.OrdinalIgnoreCase))
            {
                tokenString = tokenString.Substring("Bearer".Length).Trim();
            }
            else
            {
                context.Result = new UnauthorizedResult();
                return;
            }
            //3,Get Configuration and the Secret Key

            var configuration = context.HttpContext.RequestServices.GetService(typeof(IConfiguration)) as IConfiguration;
            var securityKey = configuration?.GetValue<string>("SecurityKey");
            //4,Verify the token
            if(!await Authenticator.VerifyTokenAsync(tokenString, securityKey))
            {
                context.Result = new UnauthorizedResult();
            }
        }
    }

使用特性

C# 复制代码
  [HttpGet]
        //添加鉴权要求
        [JwtTokenAuthFilter]
        public IEnumerable<string> Get()
        {
            return new string[] { "V1版本", "V1版本" };
        }

未添加Authorization Bearer时:

添加 Bearer Token后返回所需值

15.7,Filter的生效范围和依赖注入
  • 方法注册------当前方法有效
  • 控制器注册------当前控制器有效
  • 全局注册------全局有效

全局注册示例:

StartUp.cs中进行配置:

C# 复制代码
  //配置全局ExceptionFilter
            services.AddControllers(option =>
            {
                option.Filters.Add(typeof(Utility.Filters.CustomExceptionFilterAttribute));
            });

Demo链接

https://download.csdn.net/download/lingxiao16888/92544537?spm=1001.2014.3001.5501

相关推荐
ServBay16 小时前
C# 成为 2025 年的编程语言,7个C#技巧助力开发效率
后端·c#·.net
weixin_4239950018 小时前
unity 处理图片:截图,下载,保存
java·unity·游戏引擎
故事不长丨19 小时前
C#进制转换:从基础原理到实战应用
开发语言·c#·进制转换·16进制·2进制·10进制
liulilittle19 小时前
VEthernet 框架实现 tun2socks 的技术原理
网络·windows·c#·信息与通信·通信
云草桑20 小时前
.net AI API应用 客户发的信息提取对接上下游系统报价
ai·c#·.net·semantickernel·sk
故事不长丨21 小时前
C#File文件操作全解析:从基础用法到异常处理
服务器·开发语言·visualstudio·c#·文件操作·io流·file
呆呆敲代码的小Y1 天前
【Unity实战篇】| 游戏轮播图效果,多种实现思路及完整教程
游戏·unity·游戏引擎·实战·游戏开发·轮播图·u3d
工程师0071 天前
C# 动态编程(基于 dynamic 类型)
开发语言·c#·dynamic·动态编程
用户298698530141 天前
C#: 在Word文档中添加或移除可编辑区域
后端·c#