我决定为ASP.NET API核心2.1制作自定义中间件。
public class AuthorizeMiddleware
{
private readonly RequestDelegate _next;
private readonly AuthorizeOptions _options;
public AuthorizeMiddleware(RequestDelegate next, AuthorizeOptions options)
{
_next = next;
_options = options;
}
public async Task Invoke(HttpContext context)
{
bool hasRole = false;
if (hasRole)
{
await context.Response.WriteAsync($"Not authorized, you need role: {_options.Role}");
}
else
{
await _next.Invoke(context);
}
}
}
public struct AuthorizeOptions
{
public AuthorizeOptions(string role)
{
Role = role;
}
public string Role { get; set; }
}
当我尝试在Application.cs中使用此中间件
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
app.UseHttpsRedirection();
}
app.UseRouter(AuthenticatedRoutes(app));
app.UseMvc();
}
private IRouter AuthenticatedRoutes(IApplicationBuilder applicationBuilder)
{
IRouteBuilder builder = new RouteBuilder(applicationBuilder);
builder.MapMiddlewareGet("/api/values", appBuilder =>
{
appBuilder.UseMiddleware<AuthorizeMiddleware>(new AuthorizeOptions("User"));
appBuilder.UseMvc();
});
return builder.Build();
}
这工作得很好,但是当我删除appBuilder.UseMvc();时。从MapMiddlewareGet获得,并且我的函数调用返回的特定路由为404。
我试图将appRouter放在app.useMvc()上方。没有成功,调用_next.Invoke()时,我的中间件next函数仍然返回404。
那么,当我在appBuilder中调用useMvc()时,为什么会起作用?我在做被认为是不好的做法吗?为什么我必须在MapMiddlewareGet()中使用app.useMvc()?
答案 0 :(得分:0)
您的AuthenticatedRoutes()
试图做的是使用中间件构建路由器,因此我们可以将最终返回的IRouter用作RouterMiddleware
来处理请求。 但是,RouterMiddleware
将永远不会继续路由,只要已经有匹配的处理程序即可。结果,它不会自动将请求从一个RouterMiddlware
“分发”到另一个RouterMiddleware
。
让我们查看您的代码:
app.UseRouter(AuthenticatedRoutes(app));
您知道,这里的方法app.UseRouter()
是扩展方法,仅使用RouterMiddlware
。因此,第一个问题将是:路由器中间件如何工作?让我们看一下源代码:
public class RouterMiddleware
{
private readonly IRouter _router;
// ...
public async Task Invoke(HttpContext httpContext)
{
var context = new RouteContext(httpContext);
context.RouteData.Routers.Add(_router);
await _router.RouteAsync(context);
if (context.Handler == null){
_logger.RequestDidNotMatchRoutes();
await _next.Invoke(httpContext);
} else {
httpContext.Features[typeof(IRoutingFeature)] = new RoutingFeature(){
RouteData = context.RouteData,
};
await context.Handler(context.HttpContext);
}
}
}
如您在此处看到的,RouterMiddleware
路由上下文,并检查是否有RouterHandler
匹配:
RouterHandler
处理请求。 请注意,它将永远不会将请求分发到下一个中间件。让我们回顾一下您的路由器和RouterHandler
的工作原理:
private IRouter AuthenticatedRoutes(IApplicationBuilder applicationBuilder)
{
IRouteBuilder builder = new RouteBuilder(applicationBuilder);
builder.MapMiddlewareGet("/api/values", appBuilder =>
{
appBuilder.UseMiddleware<AuthorizeMiddleware>(new AuthorizeOptions("User"));
appBuilder.UseMvc();
});
return builder.Build();
}
看到了吗?您的路线将检查HTTP方法是否为HttpGet
,以及网址是否可以与/api/values
匹配:
如果是,则表示路由已匹配,并且将调用特定的RouterHandler
来处理请求。
RouterHandler
首先将调用AuthorizeMiddleware
的中间件appBuilder.UseMvc();
,它将调用匹配的动作appBuilder.UseMvc();
,它将终止进一步的处理,并最终产生404
响应。如果不匹配,则表示此处的路由器不匹配,将不执行任何操作,然后将请求分派到下一个中间件。