ASP.NET Core 提供了基于角色( Role )、声明( Chaim ) 和策略 ( Policy ) 等的授权方式。在实际应用中,可能采用部门( Department , 本文采用用户组 Group )、职位 ( 可继续沿用 Role )、权限( Permission )的方式进行授权。本文通过自定义 IAuthorizationPolicyProvider 进行扩展。
namespaceMicrosoft.AspNetCore.Authorization { ///<summary> /// Defines the set of data required to apply authorization rules to a resource. ///</summary> publicinterfaceIAuthorizeData { ///<summary> /// Gets or sets the policy name that determines access to the resource. ///</summary> string Policy { get; set; } ///<summary> /// Gets or sets a comma delimited list of roles that are allowed to access the resource. ///</summary> string Roles { get; set; } ///<summary> /// Gets or sets a comma delimited list of schemes from which user information is constructed. ///</summary> string AuthenticationSchemes { get; set; } } }
// 以半角逗号分隔的权限满足"需要"的其中之一即可,角色和分组也类似。 // 分组、角色和权限三者在此也是 Or 的关系,所以是在尽力去找任一匹配。 var found = false; if (requirement.AuthorizeData.Permissions != null) { var permissionsClaim = context.User.Claims.FirstOrDefault(c => string.Equals(c.Type, PermissionClaimTypes.Permission, StringComparison.OrdinalIgnoreCase)); if (permissionsClaim?.Value != null && permissionsClaim.Value.Length > 0) { var permissionsClaimSplit = SafeSplit(permissionsClaim.Value); var permissionsDataSplit = SafeSplit(requirement.AuthorizeData.Permissions); found = permissionsDataSplit.Intersect(permissionsClaimSplit).Any(); } }
if (!found && requirement.AuthorizeData.Roles != null) { var rolesClaim = context.User.Claims.FirstOrDefault(c => string.Equals(c.Type, ClaimTypes.Role, StringComparison.OrdinalIgnoreCase)); if (rolesClaim?.Value != null && rolesClaim.Value.Length > 0) { var rolesClaimSplit = SafeSplit(rolesClaim.Value); var rolesDataSplit = SafeSplit(requirement.AuthorizeData.Roles); found = rolesDataSplit.Intersect(rolesClaimSplit).Any(); } }
if (!found && requirement.AuthorizeData.Groups != null) { var groupsClaim = context.User.Claims.FirstOrDefault(c => string.Equals(c.Type, PermissionClaimTypes.Group, StringComparison.OrdinalIgnoreCase)); if (groupsClaim?.Value != null && groupsClaim.Value.Length > 0) { var groupsClaimSplit = SafeSplit(groupsClaim.Value); var groupsDataSplit = SafeSplit(requirement.AuthorizeData.Groups); found = groupsDataSplit.Intersect(groupsClaimSplit).Any(); } }
public DefaultAuthorizationPolicyProvider FallbackPolicyProvider { get; }
publicPermissionAuthorizationPolicyProvider(IOptions<AuthorizationOptions> options) { // ASP.NET Core only uses one authorization policy provider, so if the custom implementation // doesn't handle all policies (including default policies, etc.) it should fall back to an // alternate provider. // // In this sample, a default authorization policy provider (constructed with options from the // dependency injection container) is used if this custom provider isn't able to handle a given // policy name. // // If a custom policy provider is able to handle all expected policy names then, of course, this // fallback pattern is unnecessary. FallbackPolicyProvider = new DefaultAuthorizationPolicyProvider(options); }
public Task<AuthorizationPolicy> GetDefaultPolicyAsync() => FallbackPolicyProvider.GetDefaultPolicyAsync();
// For ASP.NET Core 3.0 //public Task<AuthorizationPolicy> GetFallbackPolicyAsync() => FallbackPolicyProvider.GetFallbackPolicyAsync();
public Task<AuthorizationPolicy> GetPolicyAsync(string policyName) { if (policyName.StartsWith(PolicyPrefix, StringComparison.OrdinalIgnoreCase)) { var policyValue = policyName.Substring(PolicyPrefix.Length); var authorizeData = JsonConvert.DeserializeObject<PermissionAuthorizeData>(policyValue); var policy = new AuthorizationPolicyBuilder(); policy.AddRequirements(new PermissionAuthorizationRequirement(authorizeData)); return Task.FromResult(policy.Build()); }
// If the policy name doesn't match the format expected by this policy provider, // try the fallback provider. If no fallback provider is used, this would return // Task.FromResult<AuthorizationPolicy>(null) instead. return FallbackPolicyProvider.GetPolicyAsync(policyName); } }