【问题标题】:MVC authorization inside MapWhen() is applied to all controllersMapWhen() 中的 MVC 授权应用于所有控制器
【发布时间】:2019-12-15 05:56:49
【问题描述】:

在 ASP.Net Core 3.0 Preview 7 中,我尝试编写如下代码:

public void Configure(IApplicationBuilder app) {
    app.MapWhen(context =>
        context.Request.Path.StartsWithSegments(
              new PathString("/UnsecureLog")),
        a => {
            a.UseRouting();
            a.UseEndpoints(endpoints => {
                endpoints.MapControllers();
            });
        }
    );
    
    app.UseAuthentication();
    app.UseAuthorization();

    app.MapWhen(context =>
        context.Request.Path.StartsWithSegments(
           new PathString("/SecureLog")),
        a => {
            a.UseRouting();
            a.UseEndpoints(endpoints => {
                endpoints.MapControllers()
                    .RequireAuthorization("MustBeReader");
            });
        }
    );
}

我的目标是允许在中间件中处理某些控制器而无需身份验证,我的想法是 MapWhen() 是实现这一目标的方法。

我在点击/UnsecureLog 端点时看到了这个错误:

System.InvalidOperationException: Endpoint ... contains authorization metadata,
but a middleware was not found that supports authorization.
Configure your application startup by adding app.UseAuthorization()
inside the call to Configure(..) in the application startup code.

翻译:“您如何为您不想保护的端点实施安全功能”。

我的结论是,在 any MapWhen() 块处理控制器逻辑中对RequireAuthorization("MustBeReader") 的任何调用实际上都将应用于所有 MVC 控制器路由。 p>

我当前的解决方法是删除第二个 MapWhen() 代码块中的 .RequireAuthorization("MustBeReader") 调用,并将其作为属性 ([RequireAuthorization("MustBeReader")]) 重新应用到我希望保护的那些端点。这可以正常工作并产生所需的行为。

但这不是目标,是吗?

我更愿意用类似的策略管理整个控制器组,同时完全避免其他人的安全性,并在 Configure() 中处理所有这些。相反,我必须将所需的授权要求逐个应用于每个控制器。

我希望有一种更好的方法来实现路由,从而避免此处提到的问题。也许我做错了什么。

有什么想法吗?

【问题讨论】:

  • 我也发现相反的情况也是如此......如果你调用 MapWhen() 两次并在其中的 ONE 中执行此操作.WithMetadata(new AllowAnonymousAttribute()) - 你猜怎么着?没有安全适用于任何一个。即使另一个人全面实施了大量政策。

标签: authorization middleware asp.net-core-3.0


【解决方案1】:

今天我花了一些时间在这个问题上并发布了代码,我将自己的完整答案归功于自己。感谢 mwilson 鼓励我再试一次。

在我的新方法之前,每次代码运行时,都会显示此警告...

Startup.cs(189,13): warning ASP0001: The call to UseAuthorization
should appear between app.UseRouting() and app.UseEndpoints(..)
for authorization to be correctly evaluated.

所以解决方案不仅是识别警告并注意它,还要找到一种方法来安抚编译器之神。 (你会在下面看到我还没有弄清楚如何做到这一点。)

这就是我今天所做的。我将UseAuthenticationUseAuthorization 调用放在两个不同的地方。这行得通。有点。

在这个 API 项目中,我现在可以运行匿名的不安全端点、安全端点,并且还可以运行安全的 GraphQL 端点。

FWIW,代码如下:

        public void Configure(...)
        {
            ...
            ...
            app.UseStaticFiles();
            app.UseRouting();

            app.MapWhen(
                context => (context.Request.Path
                    .StartsWithSegments(new PathString("/api"))
                ),
                a =>
                {
                    a.UseRouting();
                    a.UseAuthentication();
                    a.UseAuthorization();
                    a.UseEndpoints(endpoints =>
                    {
                        endpoints
                            .MapControllers()
                            .RequireAuthorization(...);
                    });
                }
            );

            app.UseAuthentication();
            app.UseAuthorization();

            app.UseWebSockets();
            app.UseGraphQLWebSockets<...>(...);
            app.UseGraphQL<...>(...);
        }

这行得通,但我仍然收到编译器警告。更何况,如果我太聪明了一半并尝试使用以下控制器...


    [Route("vapi/[controller]")]
    //[AllowAnonymous]
    public class VersionController : Controller
    { ...

连同这个额外的 Startup.cs 代码...

            app.MapWhen(
                context => (context.Request.Path
                    .StartsWithSegments(new PathString("/vapi"))
                ),
                a =>
                {
                    a.UseRouting();
                    // a.UseAuthentication(); <-- look, Ma, no authentication!
                    // a.UseAuthorization(); <-- look, Ma, no authorization!
                    a.UseEndpoints(endpoints =>
                    {
                        endpoints
                            .MapControllers()
                            .RequireAuthorization(...);
                    });
                }
            );

我仍然收到我的 OP 中指出的错误。 (这一切都回到我身边,就像一场古老的噩梦......)

Endpoint ....Controllers.VersionController.Version (...) contains authorization
metadata, but a middleware was not found that supports authorization.
Configure your application startup by adding app.UseAuthorization() ...

所以我要离开的问题是:我仍然无法做我想做的事情,即只保护某些控制器路径。我可以做的是(不向 Startup 添加“vapi”-path-supporting 代码)是这样的:

    [Route("api/[controller]")]
    [AllowAnonymous]
    public class VersionController : Controller
    { ...

所以...我将其称为答案,直到有人发布一组可用的代码对其进行改进。

【讨论】:

    【解决方案2】:

    需要注意的是app.UseAuthorization必须出现在app.UseRouting()app.UseEndpoints(...)之间;

    所以,它应该看起来像这样:

            app.UseRouting();
            app.UseAuthentication();
            app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller}/{action=Index}/{id?}");
            });
    

    【讨论】:

    • 可以将UseAuthorizationUseAuthorization 放在单独的 MapWhen() 调用中吗?我想知道我是否已经尝试过,但是当我有机会时会试一试。如果它有效,那么您的就是我正在寻找的解决方案。
    【解决方案3】:

    在您的 Startup 类中将以下代码向上移动(app.MapWhen 上方)。

     app.UseAuthentication();
     app.UseAuthorization();
    

    【讨论】:

    • 如果我这样做了,所有路由都会受到保护。实现与既定目标相反的目标。
    • 我觉得(据我所知)不能解决我的问题的答案应该继续积累积分,这有点有趣。还是我错过了什么,笑话在我身上?根据我的阅读,发布的解决方案使错误消息消失......同时也删除了我想要实现的所需功能。让我感到困惑。
    • @Wellspring 我想它解决了许多用户的问题,即使不是你自己的问题。
    • 谢谢!这解决了我的问题。
    【解决方案4】:

    我在类/控制器上使用Authorize-属性来强制系统要求经过身份验证的用户。如果您在此属性上指定一个参数,则它要求用户拥有此声明。 对于任何无需身份验证即可访问的控制器或方法,我们在控制器或特定方法上设置AllowAnonymous-属性。这应该推翻任何授权要求。

    【讨论】:

    • 我已经确认 [AllowAnonymous] 没有采取任何措施来防止此错误。但即便如此,我的目标是能够在中间件管道中以不同方式处理整组控制器,而不是零碎地向控制器添加属性。例如,想象一下,路由中的一组控制器以“/secured”为前缀,另一组以“/unsecured”为前缀。
    • 放弃。要么我感到非常困惑,要么我对当前的管道功能集提出了太多要求。我找到了可以走下去的有趣小巷,包括thisthis,但我想我会在黑暗中吹口哨,摆脱这种分心,继续生活,而不是在这里得到我所希望的。
    猜你喜欢
    • 1970-01-01
    • 2018-03-01
    • 2014-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-25
    • 1970-01-01
    相关资源
    最近更新 更多