我有一个应用程序,它同时具有Razor Pages和API端点。API端点的路径以"/api";。我想使用middlware添加安全头&对内联脚本使用nonce。nonce对于API终结点是不必要的,并且安全头根据请求的终结点的类型而不同。
我尝试了几种不同的方法,但仍然有问题。在我的第一次尝试(使用.Map()
扩展(中,响应标头似乎从未设置,并且我试图放入HttpContext.Items
的内容在Razor视图中不可用。使用我的第二种方法(使用.Use()
和if/else
逻辑(,可以设置响应标头,但HttpContext.Items中的项不可用。
尝试#1:
Program.cs
var builder = WebApplication.CreateBuilder(args);
// logic to register services...
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization()
## CUSTOM MIDDLEWARE ##
app.Map("/api", HandleApiRequests);
app.MapFallback(HandleRazorRequests);
## END CUSTOM MIDDLEWARE ##
app.MapRazorPages();
app.Run();
这样,响应标头和HttpContext项似乎永远不会设置。
尝试#2:
Program.cs
var builder = WebApplication.CreateBuilder(args);
// logic to register services...
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization()
## CUSTOM MIDDLEWARE ##
app.Use(async (context, next) =>
{
if (context.Request.Path.StartsWithSegments("/api"))
{
HandleApiRequests(app);
}
else
{
HandleRazorRequests(app);
}
});
## END CUSTOM MIDDLEWARE ##
app.MapRazorPages();
app.Run();
这样,就设置了响应标头,但在编辑剃刀视图时,HttpContextItem不可用。
尝试之间常见
IApplicationBuilderExtensions.cs
public static void HandleRazorRequests(this IApplicationBuilder app)
{
app.UseSecurityHeaders(new SecurityHeaderOptions { IsApi = false });
}
public static void HandleApiRequests(this IApplicationBuilder app)
{
app.UseSecurityHeaders(new SecurityHeaderOptions { IsApi = true });
}
public static IApplicationBuilder UseSecurityHeaders(this IApplicationBuilder app, SecurityHeaderOptiosn options)
{
app.UseMiddleware<SecurityHeaderMiddleware>(options);
}
SecurityHeaderMiddleware.cs
public class SecurityHeaderMiddleware
{
private readonly RequestDelegate _next;
private readonly SecurityHeaderOptions _options;
public SecurityHeaderMiddleware (RequestDelegate next, SecurityHeaderOptions options)
{
this._next = next;
this._options = options;
}
public async Task InvokeAsync(HttpContext httpContext)
{
if (this._options.IsApi)
{
httpContext.Response.Headers["Content-Security-Policy"] = "my CSP for APIs";
return await this._next(httpContext);
}
httpContext.Response.Headers["Content-Security-Policy"] = "my CSP for Razor Pages";
// Add CSP Nonce to HttpContext Items dictionary so it can be used at the view-level.
httpContext.Items["csp-nonce"] = "my nonce";
await this._next(httpContext);
}
}
我能够使用.UseWhen()
完成所需的结果问题。
app.UseWhen(ctx => ctx.Request.Path.StartsWithSegments("/api"), _appBuilder =>
{
// Apply middlware to manipulate context of requests
// to endpoints whose paths starts with "/api".
});
app.UseWhen(ctx => !ctx.Request.Path.StartsWithSegments("/api"), _appBuilder =>
{
// Apply middlware to manipulate context of requests
// to endpoints whose paths DO NOT start with "/api".
});
使用.Use()
的问题是请求不会继续到.Use()
调用下面的逻辑。它使管道分叉,再也不会回来。当您使用Use()
时,您需要完成调用中的整个管道;如果它没有以.Run()
结束,它将永远不会实际运行应用程序。
当您使用.UseWhen()
时,您会分支并为该请求添加额外的中间件,但您会返回并继续正常的路径。