主要参考了微软官方 IAuthorizationPolicyProvider 的自定义授权策略的方式,创建的权限模块。(https://docs.microsoft.com/zh-cn/aspnet/core/security/authorization/iauthorizationpolicyprovider?view=aspnetcore-3.1)
模块包含代码:
AuthorizationModule.cs 代码:
using Microsoft.Extensions.DependencyInjection; using System; using Microsoft.AspNetCore.Authorization; using Volo.Abp.Modularity; namespace WebSystem.Authorization { public class AuthorizationModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) { context.Services.AddSingleton<IAuthorizationPolicyProvider, WebPolicyProvider>(); context.Services.AddSingleton<IAuthorizationHandler, WebAuthorizationHandler>(); } } }
IWebPermissionCheck.cs 代码:
using System; using System.Collections.Generic; using System.Security.Claims; using System.Text; namespace WebSystem.Authorization { public interface IWebPermissionCheck { bool IsGranted(string[] needPermissions, ClaimsPrincipal user); } }
NullWebPermissionChecker.cs 代码:
using System; using System.Collections.Generic; using System.Security.Claims; using System.Text; using Volo.Abp.DependencyInjection; namespace WebSystem.Authorization { [Dependency(TryRegister = true)] public class NullWebPermissionChecker : IWebPermissionCheck, ITransientDependency { public bool IsGranted(string[] needPermissions, ClaimsPrincipal user) { return true; } } }
WebAuthorizationHandler.cs 代码:
using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Security.Claims; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.Extensions.Logging; using Volo.Abp.DependencyInjection; namespace WebSystem.Authorization { public class WebAuthorizationHandler : AuthorizationHandler<WebRequirement> { private readonly ILogger<WebAuthorizationHandler> _logger; protected readonly IWebPermissionCheck _webPermissionCheck; public WebAuthorizationHandler(ILogger<WebAuthorizationHandler> logger, IWebPermissionCheck webPermissionCheck) { _logger = logger; _webPermissionCheck = webPermissionCheck; } // Check whether a given MinimumAgeRequirement is satisfied or not for a particular context protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, WebRequirement requirement) { if (_webPermissionCheck.IsGranted(requirement.Permissions, context.User)) { context.Succeed(requirement); } else { _logger.LogInformation("No Permissions"); } return Task.CompletedTask; } } }
WebAuthorizeAttribute.cs 代码:
using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; namespace WebSystem.Authorization { public static class WebAutjorizeExtend { public static string[] GetPermissions(string currencyValue) { string pattern = @"[(?<content>.*?)]"; var text = Regex.Match(currencyValue, pattern).Groups["content"].Value; return text.Split(",", StringSplitOptions.RemoveEmptyEntries).ToArray(); } } public class WebAuthorizeAttribute : AuthorizeAttribute { const string POLICY_PREFIX = "NeedPermissions:[0]"; public WebAuthorizeAttribute(params string[] permissions) => Permissions = permissions; // Get or set the Age property by manipulating the underlying Policy property public string[] Permissions { get { var permissions = WebAutjorizeExtend.GetPermissions(Policy); return permissions; } set { Policy = POLICY_PREFIX.Replace("[0]", $"[{string.Join(',', value)}]"); } } } }
WebPolicyProvider.cs 代码:
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.Extensions.Options; using Volo.Abp.DependencyInjection; namespace WebSystem.Authorization { public class WebPolicyProvider : IAuthorizationPolicyProvider { const string POLICY_PREFIX = "NeedPermissions:"; public DefaultAuthorizationPolicyProvider FallbackPolicyProvider { get; } public WebPolicyProvider(IOptions<AuthorizationOptions> options) { FallbackPolicyProvider = new DefaultAuthorizationPolicyProvider(options); } public Task<AuthorizationPolicy> GetDefaultPolicyAsync() => FallbackPolicyProvider.GetDefaultPolicyAsync(); public Task<AuthorizationPolicy> GetFallbackPolicyAsync() => FallbackPolicyProvider.GetFallbackPolicyAsync(); public Task<AuthorizationPolicy> GetPolicyAsync(string policyName) { if (policyName.StartsWith(POLICY_PREFIX, StringComparison.OrdinalIgnoreCase)) { var permissionsArray = WebAutjorizeExtend.GetPermissions(policyName); if (permissionsArray.Length > 0) { var policy = new AuthorizationPolicyBuilder(); policy.AddRequirements(new WebRequirement(permissionsArray)); return Task.FromResult(policy.Build()); } } return FallbackPolicyProvider.GetPolicyAsync(policyName); } } }
WebRequirement.cs 代码:
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; namespace WebSystem.Authorization { public class WebRequirement: IAuthorizationRequirement { public string[] Permissions { get; private set; } public WebRequirement(params string[] permissions) { Permissions = permissions; } } }
使用方式:
1. 在需要的项目中添加模块依赖
2. 实现IWebPermissionCheck 中的方法替换默认的 NullWebPermissionChecker 实现,NullWebPermissionChecker 默认所有操作都是可以的,这里自己实现是指根据权限名和数据库中保存的对比,判断是否具有相应权限
在 ConfigureServices 中进行替换默认的NullWebPermissionChecker
context.Services.Replace(
ServiceDescriptor.Transient<IWebPermissionCheck, MyWebPermissionCheck>()
);
附我自己的MyWebPermissionCheck实现方式:
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Users;
using WebSystem.Authorization;
using WebSystem.Localization;
using WebSystem.Shared.Enums;
namespace WebSystem
{
public class MyWebPermissionCheck : IWebPermissionCheck, ITransientDependency
{
public ILogger<MyWebPermissionCheck> Logger { get; set; }
protected IPermissionDefinitionManager PermissionDefinitionManager { get; }
private readonly IStringLocalizer<WebSystemLoaclizationResource> _localizer;
private readonly ICurrentUser _currentUser;
private readonly IFreeSql _orm;
public MyWebPermissionCheck(IPermissionDefinitionManager permissionDefinitionManager, IStringLocalizer<WebSystemLoaclizationResource> stringLocalizer, ICurrentUser currentUser, IFreeSql orm)
{
Logger = NullLogger<MyWebPermissionCheck>.Instance;
PermissionDefinitionManager = permissionDefinitionManager;
_localizer = stringLocalizer;
_currentUser = currentUser;
_orm = orm;
}
public bool IsGranted(string[] needPermissions, ClaimsPrincipal user)
{
var claims = _currentUser.GetAllClaims();
var userIdClaim = claims?.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier);
long? userId = null;
string role = string.Empty;
if (!string.IsNullOrEmpty(userIdClaim?.Value))
{
userId = long.Parse(userIdClaim.Value);
}
else
{
return false;
}
var userRoleIdClaim = claims?.FirstOrDefault(c => c.Type == ClaimTypes.Role);
if (!string.IsNullOrEmpty(userRoleIdClaim?.Value))
{
role = userRoleIdClaim.Value;
}
if (role == RoleEnum.Admin.ToString())
{
return true;
}
var permissions = PermissionDefinitionManager.GetPermissions();
if (role == RoleEnum.Agent.ToString())
{
var agentPermissions = permissions.Where(m => (m.MultiTenancySide == Volo.Abp.MultiTenancy.MultiTenancySides.Both || m.MultiTenancySide == Volo.Abp.MultiTenancy.MultiTenancySides.Tenant) && m.IsEnabled == true);
if (agentPermissions.Any(m => needPermissions.Contains(m.Name)))
{
return true;
}
}
var isAny = _orm.Select<Models.Permission>().Where(m => m.Uid == userId && needPermissions.Contains(m.Name)).Any();
if (isAny)
{
return true;
}
return false;
}
}
}
3.具体使用多个权限之间使用英文逗号隔开