.NET Core 在本地开发期间绕过或关闭 [Authorize(Roles="")]

.NET Core Bypass or turn off [Authorize(Roles="")] during local development

我有以下代码可以在本地开发期间绕过添加身份验证,我使用的是 Azure AD 和 .NET Core。

#if !DEBUG
            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
               .AddMicrosoftIdentityWebApi(Configuration.GetSection("AzureAd"));
#endif

然而,由于我的控制器受 Authorize 属性保护,我如何在本地开发期间绕过 Controller 内的 Authorize 属性:

[Authorize(Roles = "Buyer")]
public class ProductController : ApiBaseController
{
}

在 .NET Framework 中,我有以下代码来覆盖 Authorize 属性:

public class MyAuthorizeAttribute : AuthorizeAttribute
    {
     #if DEBUG
        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            return true;
        }
     #endif
    }

.NET Core 的等效代码是什么?或者有没有其他方法可以覆盖 Startup.cs class 中的 Authorize 属性?

我认为你可以使用 IClaimsTransformation。在这种情况下,我只是给每个人添加一个角色,但是当它连接起来时,它只会在你处于开发阶段时才会这样做(注意:你需要确保环境变量设置正确,所以 IsDevelopment 有效)。

AddRolesClaimsTransformation.cs
/// <summary>
/// Adds roles to a user on the fly, this will hard code a Buyer role for everyone.
/// </summary>
public class AddRolesClaimsTransformation : IClaimsTransformation
{
    public async Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
    {
        // Clone current identity
        var clone = principal.Clone();
        var ident = (ClaimsIdentity)clone.Identity;

        ident.AddClaim(new Claim(ClaimTypes.Role, "Buyer"));

        return clone;
    }
}
Startup.cs
// Only in dev
if (builder.Environment.IsDevelopment())
{
    builder.Services.AddScoped<IClaimsTransformation, AddRolesClaimsTransformation>();
}

根据 Microsoft 文档,这应该适用于 ASP.NET Core 3.1。然而,我针对 .NET 6 对其进行了测试(在 .NET 6 中,新站点的模板将 Startup.cs 内容移至 Program.cs)。

另一方面请注意,如果您依赖 WebHostEnvironment 上的 IsDevelopment 管道,则不必使用编译器指令。这样,一旦设置了环境,无论您将其部署到那里,它都可以正常工作(例如,意外的调试构建不可能进入它不应该在的环境中)。

无需使用 [Authorize(Roles... 明确指定每个控制器所需的角色,您可以使用 [Authorize(Policy... 添加一个间接层。

这样您就可以在 StartUp class(或 IConfigureOptions<AuthorizationOptions> 服务中)决定每项政策的确切含义。包括您可能有的任何其他奇怪要求。

[Authorize(Policy= "Buyer")]
public class ProductController : ApiBaseController

...

services.AddAuthorization(o =>
{
    o.AddPolicy("Buyer", b => {
#if DEBUG
        b.RequireAuthenticatedUser();
#else
        b.RequireRole("Buyer");
#endif
    });
});

感谢 Jeremy 的正确指导,我使用以下代码让它工作:

在控制器中 class 我使用了基于策略的授权:

 [Authorize(Policy= "Buyer")]
 public class ProductController : ApiBaseController
 {
 }

在start.cs中我们可以添加基于DEBUG条件的认证&授权:

#if !DEBUG
            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
               .AddMicrosoftIdentityWebApi(config.GetSection("AzureAd"));
#endif

            services.AddAuthorization(options =>
            {
                // policy for read access
                options.AddPolicy("Buyer", policy =>
                {
#if DEBUG
                    policy.RequireAuthenticatedUser();
#else
                    policy.RequireRole("Buyer");
#endif
                });
            });

对于调试模式下的 RequireAuthenticatedUser(),我们使用以下代码在所有控制器上添加 AllowAnonymous 属性:

app.UseEndpoints(endpoints =>
            {
#if DEBUG
                endpoints.MapControllers().WithMetadata(new AllowAnonymousAttribute());
#else
                    endpoints.MapControllers();
#endif
            });