ASP.NET Core 3中的自定义授权

您有一个Web API,并且想要实现自己的授权逻辑,该怎么做?您需要做四件事。

1. 创建您的自定义授权属性

2. 在控制器上使用自定义授权属性

3. 在自定义请求管道中间件中创建授权逻辑

4. 启动时注册中间件

创建您的自定义授权属性

 1 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
 2 public class CustomAuthorizeAttribute : Attribute
 3 {
 4     public string[] AllowedUserRoles { get; private set; }
 5  
 6     public CustomAuthorizeAttribute(params string[] allowedUserRoles)
 7     {
 8         this.AllowedUserRoles = allowedUserRoles;
 9     }
10 }

在控制器上使用自定义授权属性

 1 [ApiController]
 2 [Route("[controller]")]
 3 public class WeatherForecastController : ControllerBase
 4 {
 5  
 6     [HttpGet]
 7     [CustomAuthorize("Admin", "Supervisor", "Worker")]
 8     public string Get()
 9     {
10         return "Sunny";
11     }
12 }

在自定义请求管道中间件中创建授权逻辑

 1 public static class CustomAuthorizationMiddleware
 2 {
 3     public static async Task Authorize(HttpContext httpContext, Func next)
 4     {
 5         var endpointMetaData = httpContext.GetEndpoint().Metadata;
 6  
 7         bool hasCustomAuthorizeAttribute = endpointMetaData.Any(x => x is CustomAuthorizeAttribute);
 8  
 9         if (!hasCustomAuthorizeAttribute)
10         {
11             await next.Invoke();
12             return;
13         }
14  
15         CustomAuthorizeAttribute customAuthorizeAttribute = endpointMetaData
16                 .FirstOrDefault(x => x is CustomAuthorizeAttribute) as CustomAuthorizeAttribute;
17  
18         // TODO: change authorization logic
19         bool isAuthorized = customAuthorizeAttribute.AllowedUserRoles
20             .Any(allowedRole => httpContext.User.IsInRole(allowedRole));
21  
22         if (isAuthorized)
23         {
24             await next.Invoke();
25             return;
26         }
27  
28         httpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
29         await httpContext.Response.WriteAsync("unauthorized");
30     }
31 }

启动时注册中间件

 1 public class Startup
 2 {
 3     public Startup(IConfiguration configuration)
 4     {
 5         Configuration = configuration;
 6     }
 7  
 8     public IConfiguration Configuration { get; }
 9  
10     // This method gets called by the runtime. Use this method to add services to the container.
11     public void ConfigureServices(IServiceCollection services)
12     {
13         services.AddControllers();
14     }
15  
16     // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
17     public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
18     {
19         if (env.IsDevelopment())
20         {
21             app.UseDeveloperExceptionPage();
22         }
23  
24         app.UseHttpsRedirection();
25  
26         app.UseRouting();
27  
28         app.Use(CustomAuthorizationMiddleware.Authorize);
29  
30         app.UseEndpoints(endpoints =>
31         {
32             endpoints.MapControllers();
33         });
34     }
35 }

确保在调用app.UseRouting()之后添加中间件。这样可以确保在将路由 信息添加到HttpContext 后执行您的中间件。