[英]How can I create attribute to check if the user has a claim with Identity core 2.2?
I have an application written with C#
on the top on ASP.NET Core 2.2 framework. 我在ASP.NET Core 2.2框架的顶部有一个用
C#
编写的应用程序。
I want to be able to check if a user has a claim before I allow them access to the action. 我希望能够在允许用户访问该操作之前检查用户是否有索赔。
I created an AuthorizationHandler
to check if the user has the claim like so 我创建了一个
AuthorizationHandler
来检查用户是否有这样的声明
public class ClaimExistanceHandler : AuthorizationHandler<MustHaveClaimRequirement>
{
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, MustHaveClaimRequirement requirement)
{
if (context == null
|| context.User == null
|| context.User.Identity == null
|| !context.User.Identity.IsAuthenticated
|| requirement == null
|| string.IsNullOrWhiteSpace(requirement.Type)
|| context.User.HasClaim(requirement.Type, requirement.Value))
{
context.Fail();
}
else
{
context.Succeed(requirement);
}
await Task.Yield();
}
}
}
then the requirement is as follow 那么要求如下
public class MustHaveClaimRequirement : IAuthorizationRequirement
{
public string Type { get; set; }
public string Value { get; set; }
public MustHaveClaimRequirement(string type, string value)
{
Type = type;
Value = value;
}
}
But how can I call this requirement as an attribute? 但是,我怎样才能将此要求称为属性? For example
HasPermission("do something", "1")
例如
HasPermission("do something", "1")
It seems that my HasPermission class needs to implement the AuthorizeAttribute
but not sure how would I call the handler from the attribute. 似乎我的HasPermission类需要实现
AuthorizeAttribute
但不确定如何从该属性调用处理程序。
Your primary goal here is to get the requirement into a policy , and then use or create an attribute that can specify that policy with a string name. 您的主要目标是将需求纳入策略中 ,然后使用或创建可以使用字符串名称指定该策略的属性。 Once you do that, don't need to worry about calling the handler yourself, because ASP.NET Core will take care of that for you.
完成此操作后,无需担心自己调用处理程序,因为ASP.NET Core会为您解决这一问题。
The simplest method of creating policies is to do it on app startup, as documented here . 创建策略的最简单方法是在应用启动时执行此操作,如此处所述 。 You create your policies, then use
AuthorizeAttribute
to specify which policy to attach to each endpoint. 创建策略,然后使用
AuthorizeAttribute
指定要附加到每个端点的策略。
However, doing it this way requires you to define all your policies up front. 但是,以这种方式进行操作需要您预先定义所有策略。 If that would result in you needing to create tons of different policies (because you are going to be checking lots of different claim types), and what you really want is to be able to have an attribute that specifies the claim information, there is a more dynamic way of doing it: see here .
如果那将导致您需要创建大量不同的策略(因为您将要检查许多不同的索赔类型),而您真正想要的是能够拥有一个指定索赔信息的属性,更动态的方式:请参见此处 。 You need to create an
AuthorizeAttribute
implementation that stuffs your parameter values (name and type) into a string, and create and register an IAuthorizationPolicyProvider
that can interpret that string and generate a policy with the appropriate requirement. 您需要创建一个
AuthorizeAttribute
实现,该实现将参数值(名称和类型) IAuthorizationPolicyProvider
到字符串中,并创建并注册一个IAuthorizationPolicyProvider
,它可以解释该字符串并生成具有适当要求的策略。
EDIT: It's also worth pointing out that ASP.NET Core already includes a requirement implementation for checking a claim: ClaimsAuthorizationRequirement
. 编辑:还值得指出的是,ASP.NET Core已经包含了用于检查声明的需求实现:
ClaimsAuthorizationRequirement
。 AuthorizationPolicyBuilder
has a shortcut for it ( RequireClaim
) so you can quickly create policies that check claims: AuthorizationPolicyBuilder
有一个快捷方式( RequireClaim
),因此您可以快速创建检查声明的策略:
services.AddAuthorization(options =>
{
options.AddPolicy("EmployeeOnly", policy => policy.RequireClaim("EmployeeNumber"));
});
First, you need to register policy and their related claims: 首先,您需要注册保单及其相关声明:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddAuthorization(options =>
{
//Scenario 0: Policy requires Claim0 without care what the value is
options.AddPolicy("MyPolicy0", policy => policy.RequireClaim("Claim0"));
//Scenario 1: Policy requires Claim1 with value ClaimValue1_1 OR ClaimValue 1_2
options.AddPolicy("MyPolicy1", policy => policy.RequireClaim("Claim1", "ClaimValue1_1", "ClaimValue1_2"));
//Scenario 2: Policy requires Claims2 AND Claim3 with particular values
options.AddPolicy("MyPolicy2", policy => {
policy.RequireClaim("Claim2", "ClaimValue2");
policy.RequireClaim("Claim3", "ClaimValue3"));
}
//Scenario 3: Policy requires Claims4 OR Claim5 with particular values
options.AddPolicy("MyPolicy3", policy => {
policy.RequireAssertion(ctx =>
{
return ctx.User.HasClaim("Claim4", "ClaimValue4") ||
ctx.User.HasClaim("Claim5", "ClaimValue5");
})
}
});
}
Then apply these checks whenever you need (can be applied at controller or action level): 然后在需要时应用这些检查(可以在控制器或操作级别应用):
[Authorize(Policy = "Policy1")]
public class HomeController : Controller
{
[Authorize(Policy = "Policy2")]
public ActionResult MyAction()
{
...
}
[Authorize(Policy = "Policy3")]
public ActionResult MyAnotherAction()
{
...
}
[AllowAnonymous]
public ActionResult NotSecuredAtAll()
{
...
}
}
Don't forget, if you apply multiple policies to a controller or action, then all policies must pass before access is granted (if only they don't have AllowAnonymous
attribute). 别忘了,如果您将多个策略应用于一个控制器或操作,那么所有策略必须在授予访问权限之前通过(如果只有它们没有
AllowAnonymous
属性)。
More about claims-based authorization in ASP.NET Core 2.2 有关ASP.NET Core 2.2中基于声明的授权的更多信息
I managed to write up the attribute which allows checking for claim existence after taking the feedback from nlawalker
and ivamax9
在设法获取
nlawalker
和ivamax9
的反馈后,我设法编写了允许检查索赔存在的属性
In conclusion, the HasPermissionAttribute
class takes claimType
and an optional claimValue
then creates a policy name. 总之,
HasPermissionAttribute
类采用claimType
,然后使用一个可选的claimValue
创建一个策略名称。 The attribute class looks like this 属性类如下所示
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class HasPermissionAttribute : AuthorizeAttribute
{
public const string Policy_Prefix = "HasClaim";
public const string Policy_Glue = ".";
public HasPermissionAttribute(string type, string value = null)
{
Policy = GetPolicyValue(type, value);
}
private string GetPolicyValue(string type, string value)
{
if (string.IsNullOrWhiteSpace(type))
{
throw new ArgumentNullException($"{type} cannot be null.");
}
List<string> parts = new List<string> { type.Replace(Policy_Glue, "_").Trim() };
if (!string.IsNullOrWhiteSpace(value))
{
parts.Add(value.Replace(Policy_Glue, "_"));
}
string policy = $"{Policy_Prefix}{Policy_Glue}{string.Join(Policy_Glue, parts)}";
return policy;
}
}
Now that we have a policy being applied via the HasPermissionAttribute
we now need to take the applied policy and register it using AuthorizationPolicyBuilder
which check if the given claim exists or not. 现在,我们已经通过
HasPermissionAttribute
应用了策略,我们现在需要采用已应用的策略,并使用AuthorizationPolicyBuilder
注册该策略,以检查给定的声明是否存在。 That said, I added a class called ClaimCheckerPolicyProvider
which takes the provided claim and processing the check as follow 也就是说,我添加了一个名为
ClaimCheckerPolicyProvider
的类,该类接受提供的声明并按如下方式处理检查
internal class ClaimCheckerPolicyProvider : IAuthorizationPolicyProvider
{
public Task<AuthorizationPolicy> GetDefaultPolicyAsync()
{
return Task.FromResult(new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build());
}
public Task<AuthorizationPolicy> GetPolicyAsync(string policyName)
{
if (IsClaimBasePolicy(policyName))
{
string[] parts = GetParts(policyName);
if (parts.Length > 0)
{
AuthorizationPolicyBuilder policy = GetPolicyBuilder(parts);
return Task.FromResult(policy.Build());
}
}
return Task.FromResult<AuthorizationPolicy>(null);
}
private bool IsClaimBasePolicy(string policyName)
{
return !string.IsNullOrWhiteSpace(policyName)
&& policyName.StartsWith(HasPermissionAttribute.Policy_Prefix, StringComparison.OrdinalIgnoreCase);
}
private string[] GetParts(string policyName)
{
return policyName.Split(HasPermissionAttribute.Policy_Glue, StringSplitOptions.RemoveEmptyEntries)
.Where(x => !x.Equals(HasPermissionAttribute.Policy_Prefix))
.ToArray();
}
private AuthorizationPolicyBuilder GetPolicyBuilder(string[] parts)
{
if (parts == null)
{
throw new ArgumentNullException($"{nameof(parts)} cannot be null.");
}
var length = parts.Length;
if (length == 0)
{
throw new ArgumentOutOfRangeException($"{nameof(parts)} cannot cannot be empty.");
}
var policy = new AuthorizationPolicyBuilder();
if (length > 1)
{
return policy.RequireClaim(parts[0], parts[1]);
}
return policy.RequireClaim(parts[0]);
}
}
Finally, we need to register the provider as a service. 最后,我们需要将提供程序注册为服务。 In the
ConfigureServices
of the Startup class, we add the following 在Startup类的
ConfigureServices
中,添加以下内容
services.AddTransient<IAuthorizationPolicyProvider, ClaimCheckerPolicyProvider>();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.