【问题标题】: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之前和UseAuthenticationUseAuthorization之后放置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 之后?

是有什么特殊原因还是仅仅出于性能原因?并且通过在管道中更早地移动身份验证/授权,这是否会影响响应(逆序)?

【问题讨论】:

    标签: c# asp.net-core asp.net-core-3.0 asp.net-core-middleware


    【解决方案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();
    

    关于订单的两点说明:

    1. UseRequestLocalization 仅在 UseRouting 之后有效
    2. 当涉及 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.
    }
    

    【讨论】:

      猜你喜欢
      • 2018-08-22
      • 2013-09-21
      • 2011-04-10
      • 1970-01-01
      • 2023-03-03
      • 1970-01-01
      • 2015-08-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多