如何在C#中间件app.Map的IApplicationBuilder中设置授权策略
问题描述
我有个授权策略在如下简单端点中能正常工作:
app.Map("/test", () => "hi").RequireAuthorization("WebAPI");
现在希望在使用IApplicationBuilder的app.Map("/proxy", Handle)中实现相同的授权效果,相关代码如下:
public static void Main(string[] args) { var builder = WebApplication.CreateBuilder(args); builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd")); builder.Services.AddAuthentication() .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd")); builder.Services.AddAuthorization(options => { options.AddPolicy("WebAPI", new AuthorizationPolicyBuilder(OpenIdConnectDefaults.AuthenticationScheme, JwtBearerDefaults.AuthenticationScheme) .RequireAuthenticatedUser() .Build()); options.FallbackPolicy = new AuthorizationPolicyBuilder(OpenIdConnectDefaults.AuthenticationScheme) .RequireAuthenticatedUser() .Build(); options.DefaultPolicy = options.GetPolicy("WebAPI")!; }); builder.Services.AddControllers(); builder.Services.AddHttpForwarder(); var app = builder.Build(); app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.Map("/test", () => "hi").RequireAuthorization("WebAPI"); // 此处授权正常工作 app.Map("/proxy", Handle); // 此处授权不生效 app.MapControllers(); app.Run(); } private static void Handle(IApplicationBuilder app) { app.Run(async httpContext => { if (httpContext.User.Identity is { IsAuthenticated: false }) { httpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized; await httpContext.Response.WriteAsync("Unauthorized"); return; } httpContext.Response.StatusCode = 200; await httpContext.Response.WriteAsync("Hello"); }); }
解决方案
你可以通过两种方式给/proxy端点加上相同的WebAPI授权策略:
方法一:直接在Map时添加授权约束
和/test端点的写法一致,直接在Map后链式调用RequireAuthorization,框架会自动处理授权逻辑,只有通过授权的请求才会进入Handle方法:
app.Map("/proxy", Handle).RequireAuthorization("WebAPI");
修改后Handle方法可以简化,不需要手动判断认证状态:
private static void Handle(IApplicationBuilder app) { app.Run(async httpContext => { httpContext.Response.StatusCode = 200; await httpContext.Response.WriteAsync("Hello"); }); }
方法二:在中间件内手动触发授权验证
如果需要在Handle方法内自定义授权处理逻辑,可以通过IAuthorizationService手动验证当前请求是否符合WebAPI策略:
private static void Handle(IApplicationBuilder app) { app.Run(async httpContext => { var authorizationService = httpContext.RequestServices.GetRequiredService<IAuthorizationService>(); var result = await authorizationService.AuthorizeAsync(httpContext.User, null, "WebAPI"); if (!result.Succeeded) { // 根据授权失败原因返回对应状态码 httpContext.Response.StatusCode = result.Failure?.FailureReasons.Any(r => r is DenyAuthorizationRequirement) ? (int)HttpStatusCode.Forbidden : (int)HttpStatusCode.Unauthorized; await httpContext.Response.WriteAsync("Unauthorized"); return; } httpContext.Response.StatusCode = 200; await httpContext.Response.WriteAsync("Hello"); }); }
注意事项
- 确保
UseAuthentication()和UseAuthorization()中间件在UseRouting()之后、端点映射之前正确配置,这是授权生效的必要前提。 - 优先选择方法一,它复用了ASP.NET Core的内置授权管道,减少手动代码的同时也能保证逻辑的一致性。
内容的提问来源于stack exchange,提问作者Node.JS
相关产品推荐
相关产品推荐

