如何在 ASP.NET Core 中基于 appsettings 有条件地使用授权

Posted

技术标签:

【中文标题】如何在 ASP.NET Core 中基于 appsettings 有条件地使用授权【英文标题】:How to conditionally use Authorization based on appsettings in ASP.NET Core 【发布时间】:2021-09-19 12:14:20 【问题描述】:

我有一个 ASP.NET Core 3.1 WebApi,我在其中使用基于 OAuth 的身份验证和授权。在控制器上,我添加了提供要应用的策略名称的授权属性。但是,对于我的本地开发,我想跳过身份验证/授权部分。可以说,我添加了一些 appsettings 来指示是否使用 AA。基于此,在启动类的Configure方法中,我可以有条件地使用下面的代码sn -p来激活所需的中间件。

if(configuration.GetSection("OAuth:Enabled") == true)

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

但是,我的控制器仍然装饰有 Authorize 属性。目前,除非我在每个控制器上将其注释掉,否则我无法禁用授权。有没有关于如何实现这一点的建议或任何替代选项来临时绕过基于单一配置的授权?

谢谢!

【问题讨论】:

@MajidQafouri 您提供的链接不相关。 您不需要禁用这些属性。这些只是告诉 auth 中间件该做什么的标记。没有那个中间件,它们是不活动的。当前解决方案有什么问题? still decorated with Authorize attribute. 为什么会有问题? UseAuthenticationUseAuthorization 用于启用身份验证/授权中间件,无论使用什么方法。它们并非特定于 OAuth。 OAuth 由 ASP.NET Core Identity 添加。你是否也禁用了它?你的Statup.cs 是什么样的?什么是实际问题 我希望基于单个配置更改在运行时禁用身份验证和授权。我需要这个有两个目的。一种用于简化开发人员测试的方法,这样他们就可以专注于功能更改。 2) 我们正在从 Siteminder 迁移到 OAuth。同时,这些 API 的功能也在不断变化。因此,如果我必须使用 OAuth 和不使用 OAuth 测试 API,我需要维护 2 个单独的分支并继续合并 OAuth 分支中的功能更改。所以它变成了一种开销,我们有大约 10 个 API,我们面临着同样的挑战。 另外,当前版本的 WebAPI 不使用授权。只有当我们迁移到 OAuth 时才需要它。 【参考方案1】:

可以只需创建一个自定义配置并使用编译器条件包装Authorize 属性,例如

#if !BYPASS_AUTH
[Authorize()]
#endif
public void Blah(...)

... 但这有点乱,如果你和我一样,不喜欢看到编译器指令在你的代码中乱七八糟,你可能想把它隐藏在一个自定义的授权属性或其他地方您可以按照here 所述进行命令式身份验证。

可能有多种方法可以做到这一点,但这是使用IAsyncActionFilterTypeFilterAttribute 实现的一种方法。这种方法允许我依赖注入 IAuthorizationService 进行命令式身份验证。

注意:以下代码未经测试,因此可能是拼写错误,可能需要改进...

public class CustomAuthorizeAttribute : TypeFilterAttribute

   public CustomAuthorizeAttribute(string policyName)
      : base(typeof(CustomAuthorizeAsyncActionFilterAttribute))
   
      Arguments = new object[] policyName;
   


public class CustomAuthorizeAsyncActionFilterAttribute : Attribute, IAsyncActionFilter

   private readonly IAuthorizationService _authorizationService;
   private readonly AuthSettings _authSettings;
   private readonly string _policyName;

   public CustomAuthorizeAsyncActionFilterAttribute(
      IAuthorizationService authorizationService,
      IOptions<AuthSettings> authSettings
      string policyName)
   
      _authorizationService = authorizationService;
      _authSettings = authSettings.Value;
      _policyName = policyName;
   

   public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
   
      if (_authSettings.AuthEnabled)
      
         var authorizationResult = await _authorizationService.AuthorizeAsync(context.HttpContext.User, context.ActionArguments, _policyName);
         if (authorizationResult.Succeeded)
         
            await next.Invoke();
         
         else
         
            context.Result = new ForbidResult();
         
      
      else
      
         await next.Invoke();
      
   

哦,您需要将所有[Authorize] 属性更改为[CustomAuthorize]

【讨论】:

问题是如何在运行时通过设置禁用身份验证,而不是在构建时。目前还不清楚问题代码的问题是什么。禁用身份验证的最简单方法是首先不启用它 CustomAuthorizeAsyncActionFilterAttribute 内的命令式身份验证。可以使用配置设置而不是编译器指令在运行时打开/关闭身份验证... 再次,运行时设置将如何影响用于在构建时禁用身份验证的构建时编译器指令,可能在设置更改前 1 个月?如果在生产中错误地禁用了身份验证会发生什么?这不是“小心”。 很多报告的违规行为是由意外禁用身份验证引起的 更新了答案以使其更清晰...注意:将 IOptions 注入 CustomAuthorizeAsyncActionFilterAttribute 而不是使用编译器指令(我在回答中确实解释了,但可能不清楚)。 FWIW 我认为仅注释掉 auth 中间件是正确的答案,但不确定为什么这对问题作者不起作用。我的方法的唯一好处是无需更改代码,只需配置... 注释掉授权属性有效。但我想避免这种代码更改,因为我需要在每个控制器和大约 10 个 API 中执行此操作。此外,我们正在从 Siteminder 迁移到 OAuth,并且仅当我们迁移到 OAuth 时才需要授权。当前版本没有使用它。同时,这些 API 的功能也在不断变化。因此,如果我必须使用 OAuth 和 wo OAuth 测试 API,我需要维护 2 个单独的分支并继续合并 OAuth 分支中的功能更改。因此,在所有 API 上不断维护多个分支成为一种开销

以上是关于如何在 ASP.NET Core 中基于 appsettings 有条件地使用授权的主要内容,如果未能解决你的问题,请参考以下文章

如何在 ASP.NET Core 中使用 Route 特性

ASP.NET CORE没有app.UseEndpoints()方法

如何在 ASP.NET Core 中基于 appsettings 有条件地使用授权

ASP.NET Core 6框架揭秘实例演示[02]:基于路由MVC和gRPC的应用开发

如何在 ASP.NET core rc2 中禁用浏览器缓存?

如何在 ASP.NET Core 中基于解决方案配置运行脚本