- 在 ASP.NET Core 中使用 IAuthorizationPolicyProvider 的自定义授权策略提供程序Custom Authorization Policy Providers using IAuthorizationPolicyProvider in ASP.NET Core
- 自定义策略检索Customize policy retrieval
- 参数化授权特性示例Parameterized authorize attribute example
- 自定义授权属性Custom Authorization attributes
- 自定义 IAuthorizationPolicyProviderCustom IAuthorizationPolicyProvider
- 多个授权策略提供程序Multiple authorization policy providers
- 默认策略Default policy
- 回退策略Fallback policy
- 使用自定义 IAuthorizationPolicyProviderUse a custom IAuthorizationPolicyProvider
在 ASP.NET Core 中使用 IAuthorizationPolicyProvider 的自定义授权策略提供程序Custom Authorization Policy Providers using IAuthorizationPolicyProvider in ASP.NET Core
本文内容
作者:Mike Rousos
通常,在使用基于策略的授权时,通过调用 AuthorizationOptions.AddPolicy
作为授权服务配置的一部分来注册策略。在某些情况下,可能无法(或需要)以这种方式注册所有的授权策略。在这些情况下,可以使用自定义 IAuthorizationPolicyProvider
来控制如何提供授权策略。
自定义IAuthorizationPolicyProvider可能有用的方案示例包括:
- 使用外部服务提供策略评估。
- 使用大范围的策略(例如,使用不同的房间号或年龄),因此,将每个授权策略添加到
AuthorizationOptions.AddPolicy
调用并无意义。 - 根据外部数据源(如数据库)中的信息在运行时创建策略,或通过其他机制动态确定授权要求。
从AspNetCore GitHub 存储库查看或下载示例代码。下载 dotnet/AspNetCore 存储库 ZIP 文件。解压缩文件。导航到src/Security/samples/CustomPolicyProvider项目文件夹。
自定义策略检索Customize policy retrieval
ASP.NET Core 应用使用 IAuthorizationPolicyProvider
接口的实现来检索授权策略。默认情况下, DefaultAuthorizationPolicyProvider已注册并使用。DefaultAuthorizationPolicyProvider
返回 IServiceCollection.AddAuthorization
调用中提供的 AuthorizationOptions
的策略。
自定义此行为,方法是在应用程序的依赖关系注入容器中注册不同的 IAuthorizationPolicyProvider
实现。
IAuthorizationPolicyProvider
接口包含三个 Api:
- GetPolicyAsync返回给定名称的授权策略。
- GetDefaultPolicyAsync返回默认授权策略(用于未指定策略的
[Authorize]
属性的策略)。 - 当未指定策略时, GetFallbackPolicyAsync将返回后备授权策略(授权中间件所使用的策略)。
通过实现这些 Api,你可以自定义如何提供授权策略。
参数化授权特性示例Parameterized authorize attribute example
IAuthorizationPolicyProvider
很有用的一种情况是,启用其要求依赖于参数的自定义 [Authorize]
特性。例如,在基于策略的授权文档中,使用基于时期的("AtLeast21")策略作为示例。如果应用中的不同控制器操作应该在不同年龄段的用户中可用,则使用许多不同的基于时期的策略可能会很有用。您可以使用自定义 IAuthorizationPolicyProvider
动态生成策略,而不是注册应用程序 AuthorizationOptions
所需的所有基于时期的不同策略。若要更轻松地使用策略,可以使用自定义授权属性(如 [MinimumAgeAuthorize(20)]
)来批注操作。
自定义授权属性Custom Authorization attributes
授权策略由其名称标识。前面所述的自定义 MinimumAgeAuthorizeAttribute
需要将参数映射到一个字符串,该字符串可用于检索相应的授权策略。为此,可以从 AuthorizeAttribute
派生,并使 Age
属性包装 AuthorizeAttribute.Policy
属性。
internal class MinimumAgeAuthorizeAttribute : AuthorizeAttribute
{
const string POLICY_PREFIX = "MinimumAge";
public MinimumAgeAuthorizeAttribute(int age) => Age = age;
// Get or set the Age property by manipulating the underlying Policy property
public int Age
{
get
{
if (int.TryParse(Policy.Substring(POLICY_PREFIX.Length), out var age))
{
return age;
}
return default(int);
}
set
{
Policy = $"{POLICY_PREFIX}{value.ToString()}";
}
}
}
此属性类型具有基于硬编码前缀("MinimumAge"
)的 Policy
字符串,以及通过构造函数传入的整数。
可以采用与其他 Authorize
特性相同的方式将其应用于操作,只不过它采用整数作为参数。
[MinimumAgeAuthorize(10)]
public IActionResult RequiresMinimumAge10()
自定义 IAuthorizationPolicyProviderCustom IAuthorizationPolicyProvider
使用自定义 MinimumAgeAuthorizeAttribute
可以轻松地请求所需的最短期限的授权策略。要解决的下一个问题是确保授权策略可用于所有这些不同年龄段。这就是 IAuthorizationPolicyProvider
有用的地方。
使用 MinimumAgeAuthorizationAttribute
时,授权策略名称将遵循模式 "MinimumAge" + Age
,因此自定义 IAuthorizationPolicyProvider
应通过以下方式生成授权策略:
- 正在分析策略名称的期限。
- 使用
AuthorizationPolicyBuilder
创建新AuthorizationPolicy
- 在此示例和以下示例中,假定用户通过 cookie 进行身份验证。应至少用一个授权方案名称构造
AuthorizationPolicyBuilder
或始终成功。否则,没有关于如何向用户提供质询的信息,将引发异常。 - 根据
AuthorizationPolicyBuilder.AddRequirements
的年龄将要求添加到策略。在其他情况下,你可能会改用RequireClaim
、RequireRole
或RequireUserName
。
internal class MinimumAgePolicyProvider : IAuthorizationPolicyProvider
{
const string POLICY_PREFIX = "MinimumAge";
// Policies are looked up by string name, so expect 'parameters' (like age)
// to be embedded in the policy names. This is abstracted away from developers
// by the more strongly-typed attributes derived from AuthorizeAttribute
// (like [MinimumAgeAuthorize()] in this sample)
public Task<AuthorizationPolicy> GetPolicyAsync(string policyName)
{
if (policyName.StartsWith(POLICY_PREFIX, StringComparison.OrdinalIgnoreCase) &&
int.TryParse(policyName.Substring(POLICY_PREFIX.Length), out var age))
{
var policy = new AuthorizationPolicyBuilder(CookieAuthenticationDefaults.AuthenticationScheme);
policy.AddRequirements(new MinimumAgeRequirement(age));
return Task.FromResult(policy.Build());
}
return Task.FromResult<AuthorizationPolicy>(null);
}
}
多个授权策略提供程序Multiple authorization policy providers
使用自定义 IAuthorizationPolicyProvider
实现时,请记住 ASP.NET Core 只使用 IAuthorizationPolicyProvider
的一个实例。如果自定义提供程序无法为将使用的所有策略名称提供授权策略,则该提供程序应遵从备份提供程序。
例如,假设某个应用程序需要自定义年龄策略和更传统的基于角色的策略检索。此类应用程序可使用自定义授权策略提供程序,该提供程序:
- 尝试分析策略名称。
- 如果策略名称不包含 age,则调入到不同的策略提供程序(如
DefaultAuthorizationPolicyProvider
)。
可以通过在其构造函数中创建备份策略提供程序来更新上面所示的示例 IAuthorizationPolicyProvider
实现使用 DefaultAuthorizationPolicyProvider
(如果策略名称与 "MinimumAge" + age 的预期模式不符,则使用此方法)。
private DefaultAuthorizationPolicyProvider BackupPolicyProvider { get; }
public MinimumAgePolicyProvider(IOptions<AuthorizationOptions> options)
{
// ASP.NET Core only uses one authorization policy provider, so if the custom implementation
// doesn't handle all policies it should fall back to an alternate provider.
BackupPolicyProvider = new DefaultAuthorizationPolicyProvider(options);
}
然后,可以将 GetPolicyAsync
方法更新为使用 BackupPolicyProvider
,而不是返回 null:
...
return BackupPolicyProvider.GetPolicyAsync(policyName);
默认策略Default policy
自定义 IAuthorizationPolicyProvider
除了提供命名的授权策略外,还需要实现 GetDefaultPolicyAsync
,以提供 [Authorize]
属性的授权策略,而无需指定策略名称。
在许多情况下,此授权特性只需要经过身份验证的用户,因此,你可以通过调用 RequireAuthenticatedUser
来执行必要的策略:
public Task<AuthorizationPolicy> GetDefaultPolicyAsync() =>
Task.FromResult(new AuthorizationPolicyBuilder(CookieAuthenticationDefaults.AuthenticationScheme).RequireAuthenticatedUser().Build());
与自定义 IAuthorizationPolicyProvider
的所有方面一样,你可以根据需要对其进行自定义。在某些情况下,可能需要从回退 IAuthorizationPolicyProvider
检索默认策略。
回退策略Fallback policy
自定义 IAuthorizationPolicyProvider
可以选择实现 GetFallbackPolicyAsync
来提供在结合策略时使用的策略,以及未指定策略时使用的策略。如果 GetFallbackPolicyAsync
返回非 null 策略,则在未为请求指定策略时,授权中间件会使用返回的策略。
如果不需要回退策略,则提供程序可以返回 null
或将其推迟到回退提供程序:
public Task<AuthorizationPolicy> GetFallbackPolicyAsync() =>
Task.FromResult<AuthorizationPolicy>(null);
使用自定义 IAuthorizationPolicyProviderUse a custom IAuthorizationPolicyProvider
若要从 IAuthorizationPolicyProvider
使用自定义策略,你必须:
- 与所有基于策略的授权方案一起,用依赖关系注入注册适当的
AuthorizationHandler
类型(如基于策略的授权中所述)。 - 在应用程序的依赖关系注入服务集合中注册自定义
IAuthorizationPolicyProvider
类型(在Startup.ConfigureServices
中)以替换默认策略提供程序。
services.AddSingleton<IAuthorizationPolicyProvider, MinimumAgePolicyProvider>();
Aspnet/AuthSamples GitHub 存储库中提供了一个完整的自定义 IAuthorizationPolicyProvider
示例。