为啥 `UseAuthentication` 必须放在 `UseRouting` 之后而不是之前?
Posted
技术标签:
【中文标题】为啥 `UseAuthentication` 必须放在 `UseRouting` 之后而不是之前?【英文标题】:Why does `UseAuthentication` have to be placed after `UseRouting` and not before?为什么 `UseAuthentication` 必须放在 `UseRouting` 之后而不是之前? 【发布时间】:2019-10-20 17:41:53 【问题描述】:根据documentation,中间件的顺序应该是这样的:
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
我有中间件来保护静态文件,基于this article(保护某些路由)。我遇到的问题是订单对我不起作用。如果用户已获得授权,我只能保护文件夹。所以我需要在UseStaticFiles
之前和UseAuthentication
和UseAuthorization
之后放置UseProtectFolder
:
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseProtectFolder(new ProtectFolderOptions
Path = "/Secret",
PolicyName = "Authenticated"
);
app.UseStaticFiles();
但这不会返回任何静态文件。看起来 UseRouting
正在做一些使文件不可用的事情,返回 404,因为当我将顺序更改为此时,将 UseRouting
移动到 UseStaticFiles
之后,它可以工作:
app.UseAuthentication();
app.UseAuthorization();
app.UseProtectFolder(new ProtectFolderOptions
Path = "/Secret",
PolicyName = "Authenticated"
);
app.UseStaticFiles();
app.UseRouting();
所以实际的顺序变化是UseAuthentication
放在UseRouting
之前(甚至在UseStaticFiles
之前)。
来自文档:
中间件组件的添加顺序 Startup.Configure 方法定义了中间件的顺序 组件在请求和相反的顺序被调用 回复。该顺序对于安全性、性能和 功能。
我现在的问题是:按照记录的顺序,为什么UseAuthentication
放在UseRouting
之后?
是有什么特殊原因还是仅仅出于性能原因?并且通过在管道中更早地移动身份验证/授权,这是否会影响响应(逆序)?
【问题讨论】:
【参考方案1】:发布此问题后,我在 github 上打开了一个关于 routing 的问题,以及一个关于 localization 的问题,希望获得更多信息。虽然不是所有问题都得到了直接的回答,但它帮助我找到了这个问题的答案。
看完comment of David Fowler:
UseAuthorization() -> 将查看填充的用户和当前 端点来确定是否需要应用授权策略。
我突然想到 UseAuthorization 没有问题。它适用于端点,所以我不需要它来保护文件夹。它还解释了为什么此语句仅在 UseEndpoints 语句之后才有意义。
为了全面了解我的配置,我有一个策略提供程序(包括策略)、一个 url 重写器(如 UseDefaultFiles)和保护某些文件夹的中间件。
我的结论是我可以使用下面的顺序,和记录的差不多:
// Identify the user. The only statement that is not in the order as documented
app.UseAuthentication();
// Middleware that adds policies
app.UsePolicyProvider();
// Protect the folder by policy
app.UseProtectFolder(new ProtectFolderOptions Path = "/p", PolicyName = "admin" );
// URL rewriter for serving tenant specific files
app.UseTenantStaticFiles();
// Serve the static files
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseCors();
app.UseRouting();
app.UseRequestLocalization();
app.UseAuthorization();
app.UseEndpoints();
关于订单的两点说明:
-
UseRequestLocalization 仅在 UseRouting 之后有效
当涉及 URL 重写器(如 UseDefaultFiles)时,UseStaticFiles 在 UseRouting 之后不起作用。
【讨论】:
如果您仍然碰巧有它们,您介意在此处的 cmets 中发布您在 github 上打开的那些问题的链接吗?我希望看到更多这样的讨论。 感谢您的链接!我仍然对引擎盖下到底发生了什么感到好奇,所以我做了更多的挖掘,并添加了另一个关于 UseRouting 为 UseAuthentication 和 UseAuthorization 提供什么的答案。 请更新你的答案,根据docs.microsoft.com/en-us/aspnet/core/security/…UseCors
必须放在UseRouting
之后【参考方案2】:
关于这个问题的“为什么在 UseAuth 之前使用路由”部分,我想在@Ruard 的回答中添加一件事是来自Overview of ASP.NET Core authentication 的摘录:
使用端点路由时,必须调用 UseAuthentication:
在 UseRouting 之后,路由信息可用于身份验证决策。 在 UseEndpoints 之前,以便用户在访问端点之前进行身份验证。
我仍然很好奇在调用 UseAuthentication() 之前需要哪些路由信息,所以我对源代码进行了一些挖掘,发现 UseRouting() 信息必须对 UseAuthentication() 和 UseAuthorization() 都可用只是Endpoint 类。具体来说,Endpoint.Metadata 的类型为 EndpointMetadataCollection。
EndpointMetadataCollection 只是一个对象数组,所以为了弄清楚那里可能实际填充了什么,我刚刚创建了一个空的 WebAPI 项目,在控制器上方设置了一个授权属性,放入了一些测试中间件,并在分配后立即添加了一个断点HttpContext.GetEndpoint().Metadata 到一个变量。
事实证明,它填充的内容之一是关于我添加的 Authorization 属性的数据:
事后看来,这很有意义。在您甚至不知道端点是否需要授权之前(或者在我们知道请求需要身份验证之前是否对用户进行了身份验证)就试图弄清楚请求是否已被授权,这将是愚蠢的。
我偶然发现的其他一些非常有见地的是this article by Areg Sarkissian,它真正深入到端点路由的本质,而不像微软文档那样枯燥。这个例子特别出色地展示了我上面提到的内容:
if (env.IsDevelopment())
app.UseDeveloperExceptionPage();
else
app.UseHsts();
app.UseHttpsRedirection();
app.UseRouting(routes =>
routes.MapControllers();
//Mapped route that gets attached authorization metadata using the RequireAuthorization extension method.
//This metadata will be added to the resolved endpoint for this route by the endpoint resolver
//The app.UseAuthorization() middleware later in the pipeline will get the resolved endpoint
//for the /secret route and use the authorization metadata attached to the endpoint
routes.MapGet("/secret", context =>
return context.Response.WriteAsync("secret");
).RequireAuthorization(new AuthorizeAttribute() Roles = "admin" );
);
app.UseAuthentication();
//the Authorization middleware check the resolved endpoint object
//to see if it requires authorization. If it does as in the case of
//the "/secret" route, then it will authorize the route, if it the user is in the admin role
app.UseAuthorization();
//the framework implicitly dispatches the endpoint at the end of the pipeline.
【讨论】:
以上是关于为啥 `UseAuthentication` 必须放在 `UseRouting` 之后而不是之前?的主要内容,如果未能解决你的问题,请参考以下文章
Dotnet webapp 模板有 app.UseAuthorization() 没有 app.UseAuthentication()
.Net Core 6 web api jwt 一直 401 Postman返回WWW-Authenticate Bearer没有其他提示的解决方法
为啥我们必须输入 vim ~/.vimrc 而为啥不只输入 vim ~.vimrc? [关闭]