类关系
asp.net core 封装的 Identity https://github.com/dotnet/AspNetCore/tree/main/src/Identity
定义在 Volo.Abp.Identity 模块里
[ConnectionStringName(AbpIdentityDbProperties.ConnectionStringName)]
public interface IIdentityDbContext : IEfCoreDbContext
{
DbSet<IdentityUser> Users { get; }
DbSet<IdentityRole> Roles { get; }
DbSet<IdentityClaimType> ClaimTypes { get; }
DbSet<OrganizationUnit> OrganizationUnits { get; }
DbSet<IdentitySecurityLog> SecurityLogs { get; }
DbSet<IdentityLinkUser> LinkUsers { get; }
DbSet<IdentityUserDelegation> UserDelegations { get; }
}
IdentityRoleManager, RoleManager
// asp.net core 封装的 Identity 的 RoleManager
public class RoleManager<TRole> : IDisposable where TRole : class{
public RoleManager(
IRoleStore<TRole> store,
IEnumerable<IRoleValidator<TRole>> roleValidators,
ILookupNormalizer keyNormalizer,
IdentityErrorDescriber errors,
ILogger<RoleManager<TRole>> logger){
}
}
// abp 继承 RoleManager 作为领域服务提供
public class IdentityRoleManager :
RoleManager<IdentityRole>, IDomainService, ITransientDependency
{
public IdentityRoleManager(
IdentityRoleStore store,
IEnumerable<IRoleValidator<IdentityRole>> roleValidators,
ILookupNormalizer keyNormalizer,
IdentityErrorDescriber errors,
ILogger<IdentityRoleManager> logger,
IStringLocalizer<IdentityResource> localizer,
ICancellationTokenProvider cancellationTokenProvider)
: base((IRoleStore<IdentityRole>) store, roleValidators, keyNormalizer,
errors, (ILogger<RoleManager<IdentityRole>>) logger)
{
this.Localizer = localizer;
this.CancellationTokenProvider = cancellationTokenProvider;
}
}
// 使用 RoleManager 的前提是实现 IRoleStore<IdentityRole>
// 用 IIdentityRoleRepository 实现
public class IdentityRoleStore :
IRoleStore<IdentityRole>,
IRoleClaimStore<IdentityRole>,
ITransientDependency
{
protected IIdentityRoleRepository RoleRepository { get; }
protected ILogger<IdentityRoleStore> Logger { get; }
protected IGuidGenerator GuidGenerator { get; }
/// <summary>
/// Constructs a new instance of <see cref="IdentityRoleStore"/>.
/// </summary>
public IdentityRoleStore(
IIdentityRoleRepository roleRepository,
ILogger<IdentityRoleStore> logger,
IGuidGenerator guidGenerator,
IdentityErrorDescriber describer = null)
{
RoleRepository = roleRepository;
Logger = logger;
GuidGenerator = guidGenerator;
ErrorDescriber = describer ?? new IdentityErrorDescriber();
}
}
// 类似 asp.net core identity 的 IdentityRole
public class IdentityRole : AggregateRoot<Guid>, IMultiTenant, IHasEntityVersion{
// 相比 asp.net core identity 的 IdentityRole 按照 ddd 思想去实现 多了 Claims 定义
public virtual ICollection<IdentityRoleClaim> Claims { get; protected set; }
}
public interface IIdentityRoleRepository : IBasicRepository<IdentityRole, Guid>
{
}
// IIdentityRoleRepository ef core 实现
public class EfCoreIdentityRoleRepository :
EfCoreRepository<
#nullable disable
IIdentityDbContext, IdentityRole, Guid>,
IIdentityRoleRepository,
IBasicRepository<IdentityRole, Guid>,
IBasicRepository<IdentityRole>,
IReadOnlyBasicRepository<IdentityRole>,
IRepository,
IReadOnlyBasicRepository<IdentityRole, Guid>
{
public EfCoreIdentityRoleRepository(
IDbContextProvider<IIdentityDbContext> dbContextProvider)
: base(dbContextProvider)
{
}
}
IdentityUserManager, UserManager
// asp.net core 封装的 Identity 的 UserManager
public class UserManager<TUser> : IDisposable where TUser : class
{
public UserManager(
IUserStore<TUser> store,
IOptions<IdentityOptions> optionsAccessor,
IPasswordHasher<TUser> passwordHasher,
IEnumerable<IUserValidator<TUser>> userValidators,
IEnumerable<IPasswordValidator<TUser>> passwordValidators,
ILookupNormalizer keyNormalizer,
IdentityErrorDescriber errors,
IServiceProvider services,
ILogger<UserManager<TUser>> logger)
{}
}
// abp 继承 UserManager 作为领域服务提供
public class IdentityUserManager : UserManager<IdentityUser>, IDomainService{
public IdentityUserManager(
IdentityUserStore store,
IIdentityRoleRepository roleRepository,
IIdentityUserRepository userRepository,
IOptions<IdentityOptions> optionsAccessor,
IPasswordHasher<IdentityUser> passwordHasher,
IEnumerable<IUserValidator<IdentityUser>> userValidators,
IEnumerable<IPasswordValidator<IdentityUser>> passwordValidators,
ILookupNormalizer keyNormalizer,
IdentityErrorDescriber errors,
IServiceProvider services,
ILogger<IdentityUserManager> logger,
ICancellationTokenProvider cancellationTokenProvider,
IOrganizationUnitRepository organizationUnitRepository,
ISettingProvider settingProvider)
: base(
store,
optionsAccessor,
passwordHasher,
userValidators,
passwordValidators,
keyNormalizer,
errors,
services,
logger)
{
OrganizationUnitRepository = organizationUnitRepository;
SettingProvider = settingProvider;
RoleRepository = roleRepository;
UserRepository = userRepository;
CancellationTokenProvider = cancellationTokenProvider;
}
}
// 使用 UserManager 的前提是实现 IUserStore<TUser>
// 用 IIdentityUserRepository userRepository,IIdentityRoleRepository roleRepository 实现
public class IdentityUserStore :
IUserLoginStore<IdentityUser>,
IUserRoleStore<IdentityUser>,
IUserClaimStore<IdentityUser>,
IUserPasswordStore<IdentityUser>,
IUserSecurityStampStore<IdentityUser>,
IUserEmailStore<IdentityUser>,
IUserLockoutStore<IdentityUser>,
IUserPhoneNumberStore<IdentityUser>,
IUserTwoFactorStore<IdentityUser>,
IUserAuthenticationTokenStore<IdentityUser>,
IUserAuthenticatorKeyStore<IdentityUser>,
IUserTwoFactorRecoveryCodeStore<IdentityUser>,
ITransientDependency
{
public IdentityUserStore(
IIdentityUserRepository userRepository,
IIdentityRoleRepository roleRepository,
IGuidGenerator guidGenerator,
ILogger<IdentityRoleStore> logger,
ILookupNormalizer lookupNormalizer,
IdentityErrorDescriber describer = null)
{
UserRepository = userRepository;
RoleRepository = roleRepository;
GuidGenerator = guidGenerator;
Logger = logger;
LookupNormalizer = lookupNormalizer;
ErrorDescriber = describer ?? new IdentityErrorDescriber();
}
}
// 类似 asp.net core identity 的 IdentityUser
// 大多数字段参考 asp.net core identity 的 IdentityUser
// 相比 asp.net core identity 的 IdentityUser 按照 ddd 思想去实现 多了 Claims ,Roles 定义
public class IdentityUser : FullAuditedAggregateRoot<Guid>, IUser, IHasEntityVersion{
public virtual ICollection<IdentityUserRole> Roles { get; protected set; }
public virtual ICollection<IdentityUserClaim> Claims { get; protected set; }
}
public interface IIdentityRoleRepository : IBasicRepository<IdentityRole, Guid>{
}
// IIdentityRoleRepository ef core 实现
public class EfCoreIdentityRoleRepository : EfCoreRepository<IIdentityDbContext,
IdentityRole, Guid>, IIdentityRoleRepository
{
public EfCoreIdentityRoleRepository(IDbContextProvider<IIdentityDbContext>
dbContextProvider)
: base(dbContextProvider)
{
}
}
OrganizationUnit 组织单元
在 Volo.Abp.Identity 模块里
OrganizationUnit 是在租户隔离下的表示部门相关的数据结构,如果查询父节点下的所有子节点,需 要写查询去仓库里查询
public class OrganizationUnit : FullAuditedAggregateRoot<Guid>, IMultiTenant,
IHasEntityVersion
{
public virtual Guid? TenantId { get; protected set; }
public virtual Guid? ParentId { get; internal set; }
public virtual string Code { get; internal set; }
public virtual string DisplayName { get; set; }
public virtual int EntityVersion { get; set; }
public virtual ICollection<OrganizationUnitRole> Roles { get; protected set; }
public OrganizationUnit()
{
}
public OrganizationUnit(Guid id, string displayName, Guid? parentId = null,
Guid? tenantId = null)
: base(id)
{
TenantId = tenantId;
DisplayName = displayName;
ParentId = parentId;
Roles = new Collection<OrganizationUnitRole>();
}
public static string CreateCode(params int[] numbers)
{
if (numbers.IsNullOrEmpty())
{
return null;
}
return numbers.Select(number => number.ToString(new string('0',
OrganizationUnitConsts.CodeUnitLength))).JoinAsString(".");
}
public static string AppendCode(string parentCode, string childCode)
{
if (childCode.IsNullOrEmpty())
{
throw new ArgumentNullException(nameof(childCode),
"childCode can not be null or empty.");
}
if (parentCode.IsNullOrEmpty())
{
return childCode;
}
return parentCode + "." + childCode;
}
public static string GetRelativeCode(string code, string parentCode)
{
if (code.IsNullOrEmpty())
{
throw new ArgumentNullException(nameof(code),
"code can not be null or empty.");
}
if (parentCode.IsNullOrEmpty())
{
return code;
}
if (code.Length == parentCode.Length)
{
return null;
}
return code.Substring(parentCode.Length + 1);
}
/// <summary>
/// Calculates next code for given code.
/// Example: if code = "00019.00055.00001" returns "00019.00055.00002".
/// </summary>
/// <param name="code">The code.</param>
public static string CalculateNextCode(string code)
{
if (code.IsNullOrEmpty())
{
throw new ArgumentNullException(nameof(code),
"code can not be null or empty.");
}
var parentCode = GetParentCode(code);
var lastUnitCode = GetLastUnitCode(code);
return AppendCode(parentCode, CreateCode(Convert.ToInt32(lastUnitCode) + 1));
}
/// <summary>
/// Gets the last unit code.
/// Example: if code = "00019.00055.00001" returns "00001".
/// </summary>
/// <param name="code">The code.</param>
public static string GetLastUnitCode(string code)
{
if (code.IsNullOrEmpty())
{
throw new ArgumentNullException(nameof(code),
"code can not be null or empty.");
}
var splittedCode = code.Split('.');
return splittedCode[splittedCode.Length - 1];
}
/// <summary>
/// Gets parent code.
/// Example: if code = "00019.00055.00001" returns "00019.00055".
/// </summary>
/// <param name="code">The code.</param>
public static string GetParentCode(string code)
{
if (code.IsNullOrEmpty())
{
throw new ArgumentNullException(nameof(code),
"code can not be null or empty.");
}
var splittedCode = code.Split('.');
if (splittedCode.Length == 1)
{
return null;
}
return splittedCode.Take(splittedCode.Length - 1).JoinAsString(".");
}
public virtual void AddRole(Guid roleId)
{
Check.NotNull(roleId, nameof(roleId));
if (IsInRole(roleId))
{
return;
}
Roles.Add(new OrganizationUnitRole(roleId, Id, TenantId));
}
public virtual void RemoveRole(Guid roleId)
{
Check.NotNull(roleId, nameof(roleId));
if (!IsInRole(roleId))
{
return;
}
Roles.RemoveAll(r => r.RoleId == roleId);
}
public virtual bool IsInRole(Guid roleId)
{
Check.NotNull(roleId, nameof(roleId));
return Roles.Any(r => r.RoleId == roleId);
}
}
public interface IOrganizationUnitRepository :
IBasicRepository<OrganizationUnit, Guid>,
IBasicRepository<OrganizationUnit>,
IReadOnlyBasicRepository<OrganizationUnit>,
IRepository,
IReadOnlyBasicRepository<OrganizationUnit, Guid>
{
}
//通过 OrganizationUnitManager 领域服务进行管理
public class OrganizationUnitManager : DomainService
{
protected IOrganizationUnitRepository OrganizationUnitRepository { get; }
protected IStringLocalizer<IdentityResource> Localizer { get; }
protected IIdentityRoleRepository IdentityRoleRepository { get; }
protected ICancellationTokenProvider CancellationTokenProvider { get; }
public OrganizationUnitManager(
IOrganizationUnitRepository organizationUnitRepository,
IStringLocalizer<IdentityResource> localizer,
IIdentityRoleRepository identityRoleRepository,
ICancellationTokenProvider cancellationTokenProvider)
{
OrganizationUnitRepository = organizationUnitRepository;
Localizer = localizer;
IdentityRoleRepository = identityRoleRepository;
CancellationTokenProvider = cancellationTokenProvider;
}
}
MultiTenancy
public class Tenant : FullAuditedAggregateRoot<Guid>, IHasEntityVersion
{
public virtual string Name { get; protected set; }
public virtual int EntityVersion { get; protected set; }
public virtual List<TenantConnectionString> ConnectionStrings { get; protected set; }
protected Tenant()
{
}
protected internal Tenant(Guid id, [NotNull] string name)
: base(id)
{
SetName(name);
ConnectionStrings = new List<TenantConnectionString>();
}
[CanBeNull]
public virtual string FindDefaultConnectionString()
{
return FindConnectionString(Data.ConnectionStrings.DefaultConnectionStringName);
}
[CanBeNull]
public virtual string FindConnectionString(string name)
{
return ConnectionStrings.FirstOrDefault(c => c.Name == name)?.Value;
}
public virtual void SetDefaultConnectionString(string connectionString)
{
SetConnectionString(Data.ConnectionStrings.DefaultConnectionStringName,
connectionString);
}
public virtual void SetConnectionString(string name, string connectionString)
{
var tenantConnectionString = ConnectionStrings.FirstOrDefault(x => x.Name == name);
if (tenantConnectionString != null)
{
tenantConnectionString.SetValue(connectionString);
}
else
{
ConnectionStrings.Add(new TenantConnectionString(Id, name, connectionString));
}
}
public virtual void RemoveDefaultConnectionString()
{
RemoveConnectionString(Data.ConnectionStrings.DefaultConnectionStringName);
}
public virtual void RemoveConnectionString(string name)
{
var tenantConnectionString = ConnectionStrings.FirstOrDefault(x => x.Name == name);
if (tenantConnectionString != null)
{
ConnectionStrings.Remove(tenantConnectionString);
}
}
protected internal virtual void SetName([NotNull] string name)
{
Name = Check.NotNullOrWhiteSpace(name, nameof(name), TenantConsts.MaxNameLength);
}
}
public interface ITenantRepository : IBasicRepository<Tenant, Guid>{
}
//利用 ITenantRepository 进行管理
public interface ITenantManager : IDomainService
{
[NotNull]
Task<Tenant> CreateAsync([NotNull] string name);
Task ChangeNameAsync([NotNull] Tenant tenant, [NotNull] string name);
}
namespace Volo.Abp.AspNetCore.Mvc.MultiTenancy;
public interface IAbpTenantAppService : IApplicationService
{
Task<FindTenantResultDto> FindTenantByNameAsync(string name);
Task<FindTenantResultDto> FindTenantByIdAsync(Guid id);
}
namespace Volo.Abp.TenantManagement
{
public interface ITenantAppService :
ICrudAppService<TenantDto, Guid, GetTenantsInput, TenantCreateDto, TenantUpdateDto>,
ICrudAppService<TenantDto, TenantDto, Guid, GetTenantsInput, TenantCreateDto,
TenantUpdateDto>,
IReadOnlyAppService<TenantDto, TenantDto, Guid, GetTenantsInput>,
IApplicationService,
IRemoteService,
ICreateUpdateAppService<TenantDto, Guid, TenantCreateDto, TenantUpdateDto>,
ICreateAppService<TenantDto, TenantCreateDto>,
IUpdateAppService<TenantDto, Guid, TenantUpdateDto>,
IDeleteAppService<Guid>
{
Task<string> GetDefaultConnectionStringAsync(Guid id);
Task UpdateDefaultConnectionStringAsync(Guid id, string defaultConnectionString);
Task DeleteDefaultConnectionStringAsync(Guid id);
}
}
public class TenantAppService : TenantManagementAppServiceBase, ITenantAppService
{
protected IDataSeeder DataSeeder { get; }
protected ITenantRepository TenantRepository { get; }
protected ITenantManager TenantManager { get; }
protected IDistributedEventBus DistributedEventBus { get; }
public TenantAppService(
ITenantRepository tenantRepository,
ITenantManager tenantManager,
IDataSeeder dataSeeder,
IDistributedEventBus distributedEventBus)
{
DataSeeder = dataSeeder;
TenantRepository = tenantRepository;
TenantManager = tenantManager;
DistributedEventBus = distributedEventBus;
}
}
public class AbpTenantAppService : ApplicationService, IAbpTenantAppService
{
protected ITenantStore TenantStore { get; }
public AbpTenantAppService(ITenantStore tenantStore)
{
TenantStore = tenantStore;
}
}
Permission
PermissionDefinition 表
namespace Volo.Abp.PermissionManagement;
public class PermissionDefinitionRecord : BasicAggregateRoot<Guid>, IHasExtraProperties
{
public string GroupName { get; set; }
public string Name { get; set; }
public string ParentName { get; set; }
public string DisplayName { get; set; }
public bool IsEnabled { get; set; }
public MultiTenancySides MultiTenancySide { get; set; }
/// <summary>
/// Comma separated list of provider names.
/// </summary>
public string Providers { get; set; }
/// <summary>
/// Serialized string to store info about the state checkers.
/// </summary>
public string StateCheckers { get; set; }
public ExtraPropertyDictionary ExtraProperties { get; protected set; }
public PermissionDefinitionRecord()
{
ExtraProperties = new ExtraPropertyDictionary();
this.SetDefaultsForExtraProperties();
}
public PermissionDefinitionRecord(
Guid id,
string groupName,
string name,
string parentName,
string displayName,
bool isEnabled = true,
MultiTenancySides multiTenancySide = MultiTenancySides.Both,
string providers = null,
string stateCheckers = null)
: base(id)
{
GroupName =
Check.NotNullOrWhiteSpace(
groupName, nameof(groupName), PermissionGroupDefinitionRecordConsts.MaxNameLength);
Name =
Check.NotNullOrWhiteSpace(
name, nameof(name), PermissionDefinitionRecordConsts.MaxNameLength);
ParentName =
Check.Length(
parentName, nameof(parentName), PermissionDefinitionRecordConsts.MaxNameLength);
DisplayName =
Check.NotNullOrWhiteSpace(
displayName, nameof(
displayName), PermissionDefinitionRecordConsts.MaxDisplayNameLength);
IsEnabled = isEnabled;
MultiTenancySide = multiTenancySide;
Providers = providers;
StateCheckers = stateCheckers;
ExtraProperties = new ExtraPropertyDictionary();
this.SetDefaultsForExtraProperties();
}
}
// PermissionGroupDefinition 表
public class PermissionGroupDefinitionRecord : BasicAggregateRoot<Guid>, IHasExtraProperties
{
public string Name { get; set; }
public string DisplayName { get; set; }
public ExtraPropertyDictionary ExtraProperties { get; protected set; }
public PermissionGroupDefinitionRecord()
{
ExtraProperties = new ExtraPropertyDictionary();
this.SetDefaultsForExtraProperties();
}
}
已经和用户或角色或客户端绑定的 Permission
namespace Volo.Abp.PermissionManagement;
public class PermissionGrant : Entity<Guid>, IMultiTenant
{
public virtual Guid? TenantId { get; protected set; }
[NotNull]
public virtual string Name { get; protected set; }
[NotNull]
public virtual string ProviderName { get; protected set; }
[CanBeNull]
public virtual string ProviderKey { get; protected internal set; }
protected PermissionGrant()
{
}
public PermissionGrant(
Guid id,
[NotNull] string name,
[NotNull] string providerName,
[CanBeNull] string providerKey,
Guid? tenantId = null)
{
Check.NotNull(name, nameof(name));
Id = id;
Name = Check.NotNullOrWhiteSpace(name, nameof(name));
ProviderName = Check.NotNullOrWhiteSpace(providerName, nameof(providerName));
ProviderKey = providerKey;
TenantId = tenantId;
}
}
namespace Volo.Abp.Authorization.Permissions
{
public interface IPermissionStore
{
Task<bool> IsGrantedAsync(string name, string providerName, string providerKey);
Task<MultiplePermissionGrantResult> IsGrantedAsync(
string[] names,
string providerName,
string providerKey);
}
}
namespace Volo.Abp.PermissionManagement
{
public interface IPermissionGrantRepository :
IBasicRepository<PermissionGrant, Guid>,
IBasicRepository<PermissionGrant>,
IReadOnlyBasicRepository<PermissionGrant>,
IRepository,
IReadOnlyBasicRepository<PermissionGrant, Guid>
{
Task<PermissionGrant> FindAsync(
string name,
string providerName,
string providerKey,
CancellationToken cancellationToken = default (CancellationToken));
Task<List<PermissionGrant>> GetListAsync(
string providerName,
string providerKey,
CancellationToken cancellationToken = default (CancellationToken));
Task<List<PermissionGrant>> GetListAsync(
string[] names,
string providerName,
string providerKey,
CancellationToken cancellationToken = default (CancellationToken));
}
}
// Volo.Abp.PermissionManagement 管理模块
namespace Volo.Abp.PermissionManagement
{
public class PermissionStore : IPermissionStore, ITransientDependency
{
public
#nullable disable
ILogger<PermissionStore> Logger { get; set; }
protected IPermissionGrantRepository PermissionGrantRepository { get; }
protected IPermissionDefinitionManager PermissionDefinitionManager { get; }
protected IDistributedCache<PermissionGrantCacheItem> Cache { get; }
public PermissionStore(
IPermissionGrantRepository permissionGrantRepository,
IDistributedCache<PermissionGrantCacheItem> cache,
IPermissionDefinitionManager permissionDefinitionManager)
{
this.PermissionGrantRepository = permissionGrantRepository;
this.Cache = cache;
this.PermissionDefinitionManager = permissionDefinitionManager;
this.Logger = (ILogger<PermissionStore>) NullLogger<PermissionStore>.Instance;
}
}
}
namespace Volo.Abp.PermissionManagement;
public interface IPermissionManager
{
Task<PermissionWithGrantedProviders>
GetAsync(string permissionName, string providerName, string providerKey);
Task<MultiplePermissionWithGrantedProviders>
GetAsync(string[] permissionNames, string provideName, string providerKey);
Task<List<PermissionWithGrantedProviders>>
GetAllAsync([NotNull] string providerName, [NotNull] string providerKey);
Task SetAsync(string permissionName,
string providerName, string providerKey, bool isGranted);
Task<PermissionGrant> UpdateProviderKeyAsync(
PermissionGrant permissionGrant, string providerKey);
Task DeleteAsync(string providerName, string providerKey);
}
public class PermissionManager : IPermissionManager, ISingletonDependency
{
protected IPermissionGrantRepository
PermissionGrantRepository { get; }
protected IPermissionDefinitionManager
PermissionDefinitionManager { get; }
protected ISimpleStateCheckerManager<PermissionDefinition>
SimpleStateCheckerManager { get; }
protected IGuidGenerator GuidGenerator { get; }
protected ICurrentTenant CurrentTenant { get; }
protected IReadOnlyList<IPermissionManagementProvider>
ManagementProviders => _lazyProviders.Value;
protected PermissionManagementOptions Options { get; }
protected IDistributedCache<PermissionGrantCacheItem> Cache { get; }
private readonly Lazy<List<IPermissionManagementProvider>> _lazyProviders;
public PermissionManager(
IPermissionDefinitionManager permissionDefinitionManager,
ISimpleStateCheckerManager<PermissionDefinition> simpleStateCheckerManager,
IPermissionGrantRepository permissionGrantRepository,
IServiceProvider serviceProvider,
IGuidGenerator guidGenerator,
IOptions<PermissionManagementOptions> options,
ICurrentTenant currentTenant,
IDistributedCache<PermissionGrantCacheItem> cache)
{
GuidGenerator = guidGenerator;
CurrentTenant = currentTenant;
Cache = cache;
SimpleStateCheckerManager = simpleStateCheckerManager;
PermissionGrantRepository = permissionGrantRepository;
PermissionDefinitionManager = permissionDefinitionManager;
Options = options.Value;
_lazyProviders = new Lazy<List<IPermissionManagementProvider>>(
() => Options
.ManagementProviders
.Select(c => serviceProvider.GetRequiredService(c)
as IPermissionManagementProvider)
.ToList(),
true
);
}
}
应用服务
Volo.Abp.Account 模块也定义了用户管理服务,但是提供的方法比较少,只能做参考实现
public interface IAccountAppService : IApplicationService
{
Task<IdentityUserDto> RegisterAsync(RegisterDto input);
Task SendPasswordResetCodeAsync(SendPasswordResetCodeDto input);
Task<bool> VerifyPasswordResetTokenAsync(VerifyPasswordResetTokenInput input);
Task ResetPasswordAsync(ResetPasswordDto input);
}
利用 abp 提供的基础服务构建用户自己的服务
- RoleAppService
- UserAppService
- OrganizationUnitAppService
- TenantAppService
相关数据库表
AbpPermissionGroups AbpPermissions AbpPermissionGrants
PermissionDefinition
保存在代码里的叫 static,保存在数据库的叫 动态 Permission ,程序会合并者俩者 volo.Abp.PermissionManagement 模块启动的时候会把数据库不存在的 Permission 保存到数据库
Volo.Abp.Authorization 模块定义
PermissionGroupDefinition,PermissionDefinition
namespace Volo.Abp.Authorization.Permissions;
public class PermissionGroupDefinition : ICanAddChildPermission
{
/// <summary>
/// Unique name of the group.
/// </summary>
public string Name { get; }
public Dictionary<string, object> Properties { get; }
public ILocalizableString DisplayName {
get => _displayName;
set => _displayName = Check.NotNull(value, nameof(value));
}
private ILocalizableString _displayName;
public IReadOnlyList<PermissionDefinition> Permissions =>
_permissions.ToImmutableList();
private readonly List<PermissionDefinition> _permissions;
public object this[string name] {
get => Properties.GetOrDefault(name);
set => Properties[name] = value;
}
protected internal PermissionGroupDefinition(
string name,
ILocalizableString displayName = null)
{
Name = name;
DisplayName = displayName ?? new FixedLocalizableString(Name);
Properties = new Dictionary<string, object>();
_permissions = new List<PermissionDefinition>();
}
public virtual PermissionDefinition AddPermission(
[NotNull] string name,
ILocalizableString displayName = null,
MultiTenancySides multiTenancySide = MultiTenancySides.Both,
bool isEnabled = true)
{
var permission = new PermissionDefinition(
name,
displayName,
multiTenancySide,
isEnabled
);
_permissions.Add(permission);
return permission;
}
public virtual List<PermissionDefinition> GetPermissionsWithChildren()
{
var permissions = new List<PermissionDefinition>();
foreach (var permission in _permissions)
{
AddPermissionToListRecursively(permissions, permission);
}
return permissions;
}
private void AddPermissionToListRecursively(
List<PermissionDefinition> permissions, PermissionDefinition permission)
{
permissions.Add(permission);
foreach (var child in permission.Children)
{
AddPermissionToListRecursively(permissions, child);
}
}
public override string ToString()
{
return $"[{nameof(PermissionGroupDefinition)} {Name}]";
}
[CanBeNull]
public PermissionDefinition GetPermissionOrNull([NotNull] string name)
{
Check.NotNull(name, nameof(name));
return GetPermissionOrNullRecursively(Permissions, name);
}
private PermissionDefinition GetPermissionOrNullRecursively(
IReadOnlyList<PermissionDefinition> permissions, string name)
{
foreach (var permission in permissions)
{
if (permission.Name == name)
{
return permission;
}
var childPermission = GetPermissionOrNullRecursively(
permission.Children, name);
if (childPermission != null)
{
return childPermission;
}
}
return null;
}
}
public class PermissionDefinition :
IHasSimpleStateCheckers<PermissionDefinition>,
ICanAddChildPermission
{
public string Name { get; }
public PermissionDefinition Parent { get; private set; }
public MultiTenancySides MultiTenancySide { get; set; }
public List<string> Providers { get; }
public List<ISimpleStateChecker<PermissionDefinition>> StateCheckers { get; }
public ILocalizableString DisplayName {
get => _displayName;
set => _displayName = Check.NotNull(value, nameof(value));
}
private ILocalizableString _displayName;
public IReadOnlyList<PermissionDefinition> Children => _children.ToImmutableList();
private readonly List<PermissionDefinition> _children;
public Dictionary<string, object> Properties { get; }
public bool IsEnabled { get; set; }
public object this[string name] {
get => Properties.GetOrDefault(name);
set => Properties[name] = value;
}
protected internal PermissionDefinition(
[NotNull] string name,
ILocalizableString displayName = null,
MultiTenancySides multiTenancySide = MultiTenancySides.Both,
bool isEnabled = true)
{
Name = Check.NotNull(name, nameof(name));
DisplayName = displayName ?? new FixedLocalizableString(name);
MultiTenancySide = multiTenancySide;
IsEnabled = isEnabled;
Properties = new Dictionary<string, object>();
Providers = new List<string>();
StateCheckers = new List<ISimpleStateChecker<PermissionDefinition>>();
_children = new List<PermissionDefinition>();
}
public virtual PermissionDefinition AddChild(
[NotNull] string name,
ILocalizableString displayName = null,
MultiTenancySides multiTenancySide = MultiTenancySides.Both,
bool isEnabled = true)
{
var child = new PermissionDefinition(
name,
displayName,
multiTenancySide,
isEnabled)
{
Parent = this
};
_children.Add(child);
return child;
}
PermissionDefinition ICanAddChildPermission.AddPermission(
string name,
ILocalizableString displayName = null,
MultiTenancySides multiTenancySide = MultiTenancySides.Both,
bool isEnabled = true)
{
return this.AddChild(name, displayName, multiTenancySide, isEnabled);
}
/// <summary>
/// Sets a property in the <see cref="Properties"/> dictionary.
/// This is a shortcut for nested calls on this object.
/// </summary>
public virtual PermissionDefinition WithProperty(string key, object value)
{
Properties[key] = value;
return this;
}
/// <summary>
/// Adds one or more providers to the <see cref="Providers"/> list.
/// This is a shortcut for nested calls on this object.
/// </summary>
public virtual PermissionDefinition WithProviders(params string[] providers)
{
if (!providers.IsNullOrEmpty())
{
Providers.AddIfNotContains(providers);
}
return this;
}
public override string ToString()
{
return $"[{nameof(PermissionDefinition)} {Name}]";
}
}
IPermissionDefinitionContext
权限及权限组都加到 PermissionDefinitionContext 此类用
public Dictionary<string, PermissionGroupDefinition> Groups { get; }
保存加入的组
public interface IPermissionDefinitionContext
{
//TODO: Add Get methods to find and modify a permission or group.
IServiceProvider ServiceProvider { get; }
PermissionGroupDefinition GetGroup([NotNull] string name);
PermissionGroupDefinition GetGroupOrNull(string name);
PermissionGroupDefinition AddGroup(
[NotNull] string name,
ILocalizableString displayName = null);
void RemoveGroup(string name);
PermissionDefinition GetPermissionOrNull([NotNull] string name);
}
IPermissionDefinitionProvider
所有的 IPermissionDefinitionProvider 会被 abp 发现被被转化为 asp.net core 策略 policy abp 会自动生成策略处理类,处理类会对用户的 claim 里的 value 和 权限里定义的进行比对
IPermissionDefinitionManager 管理所有定义的 IPermissionDefinition
public interface IPermissionDefinitionProvider
{
void PreDefine(IPermissionDefinitionContext context);
void Define(IPermissionDefinitionContext context);
void PostDefine(IPermissionDefinitionContext context);
}
public abstract class PermissionDefinitionProvider :
IPermissionDefinitionProvider, ITransientDependency
{
public virtual void PreDefine(IPermissionDefinitionContext context)
{
}
public abstract void Define(IPermissionDefinitionContext context);
public virtual void PostDefine(IPermissionDefinitionContext context)
{
}
}
AbpAuthorizationModule 自动注入 IPermissionDefinition 及加入 asp.net core 核心服务
namespace Volo.Abp.Authorization;
[DependsOn(
typeof(AbpAuthorizationAbstractionsModule),
typeof(AbpSecurityModule),
typeof(AbpLocalizationModule),
typeof(AbpMultiTenancyModule)
)]
public class AbpAuthorizationModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
context.Services.OnRegistered(AuthorizationInterceptorRegistrar.RegisterIfNeeded);
AutoAddDefinitionProviders(context.Services);
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
/**
此方法内部也会调用 AddAuthorizationCore
context.Services.AddAuthentication(p => {
});
*/
//注入 asp.net core 关于授权的核心服务
context.Services.AddAuthorizationCore();
// 按照 asp.net core 要去注入 handler
context.Services.AddSingleton<
IAuthorizationHandler, PermissionRequirementHandler>();
context.Services.AddSingleton<
IAuthorizationHandler, PermissionsRequirementHandler>();
context.Services.TryAddTransient<DefaultAuthorizationPolicyProvider>();
Configure<AbpPermissionOptions>(options =>
{
options.ValueProviders.Add<UserPermissionValueProvider>();
options.ValueProviders.Add<RolePermissionValueProvider>();
options.ValueProviders.Add<ClientPermissionValueProvider>();
});
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<AbpAuthorizationResource>();
});
Configure<AbpLocalizationOptions>(options =>
{
options.Resources
.Add<AbpAuthorizationResource>("en")
.AddVirtualJson("/Volo/Abp/Authorization/Localization");
});
Configure<AbpExceptionLocalizationOptions>(options =>
{
options.MapCodeNamespace("Volo.Authorization",
typeof(AbpAuthorizationResource));
});
}
//发现 IPermissionDefinitionProvider 并赋值给 AbpPermissionOptions 类
private static void AutoAddDefinitionProviders(IServiceCollection services)
{
var definitionProviders = new List<Type>();
//在注册的时候拿到 ImplementationType
// 赋值给 AbpPermissionOptions 的得 DefinitionProviders
services.OnRegistered(context =>
{
if (typeof(IPermissionDefinitionProvider).
IsAssignableFrom(context.ImplementationType))
{
definitionProviders.Add(context.ImplementationType);
}
});
services.Configure<AbpPermissionOptions>(options =>
{
options.DefinitionProviders.AddIfNotContains(definitionProviders);
});
}
}
public class AbpPermissionOptions
{
public ITypeList<IPermissionDefinitionProvider> DefinitionProviders { get; }
public ITypeList<IPermissionValueProvider> ValueProviders { get; }
public HashSet<string> DeletedPermissions { get; }
public HashSet<string> DeletedPermissionGroups { get; }
public AbpPermissionOptions()
{
DefinitionProviders = new TypeList<IPermissionDefinitionProvider>();
ValueProviders = new TypeList<IPermissionValueProvider>();
DeletedPermissions = new HashSet<string>();
DeletedPermissionGroups = new HashSet<string>();
}
}
StaticPermissionDefinitionStore
namespace Volo.Abp.Authorization.Permissions;
// PermissionDefinitionStore 单例,并且字段做成懒加载,这样才能保证注入时
// 生成的 PermissionGroupDefinitions ,PermissionDefinitions 不会为空
public class StaticPermissionDefinitionStore :
IStaticPermissionDefinitionStore, ISingletonDependency
{
protected IDictionary<string, PermissionGroupDefinition> PermissionGroupDefinitions =>
_lazyPermissionGroupDefinitions.Value;
private readonly Lazy<Dictionary<string, PermissionGroupDefinition>>
_lazyPermissionGroupDefinitions;
protected IDictionary<string, PermissionDefinition> PermissionDefinitions =>
_lazyPermissionDefinitions.Value;
private readonly Lazy<Dictionary<string, PermissionDefinition>>
_lazyPermissionDefinitions;
protected AbpPermissionOptions Options { get; }
private readonly IServiceProvider _serviceProvider;
//AbpPermissionOptions 里可以获取所有的 PermissionDefinition 定义
public StaticPermissionDefinitionStore(
IServiceProvider serviceProvider,
IOptions<AbpPermissionOptions> options)
{
_serviceProvider = serviceProvider;
Options = options.Value;
//所有组里的所有 PermissionDefinition
_lazyPermissionDefinitions = new Lazy<Dictionary<string, PermissionDefinition>>(
CreatePermissionDefinitions,
isThreadSafe: true
);
//通过 AbpPermissionOptions 获取所有的权限组
_lazyPermissionGroupDefinitions = new Lazy<Dictionary<string,
PermissionGroupDefinition>>(
CreatePermissionGroupDefinitions,
isThreadSafe: true
);
}
protected virtual Dictionary<string, PermissionDefinition>
CreatePermissionDefinitions()
{
var permissions = new Dictionary<string, PermissionDefinition>();
//遍历组把组里的 PermissionDefinition 赋值给 permissions 字典
foreach (var groupDefinition in PermissionGroupDefinitions.Values)
{
foreach (var permission in groupDefinition.Permissions)
{
// 反复递归把组里的所有权限加入 permissions 字典
AddPermissionToDictionaryRecursively(permissions, permission);
}
}
//返回所有组里所有 PermissionDefinition
return permissions;
}
//反复递归把嵌套关系转换字典
protected virtual void AddPermissionToDictionaryRecursively(
Dictionary<string, PermissionDefinition> permissions,
PermissionDefinition permission)
{
if (permissions.ContainsKey(permission.Name))
{
throw new AbpException("Duplicate permission name: " + permission.Name);
}
permissions[permission.Name] = permission;
foreach (var child in permission.Children)
{
AddPermissionToDictionaryRecursively(permissions, child);
}
}
// AbpPermissionOptions 获取所有的 PermissionGroupDefinition
protected virtual Dictionary<string, PermissionGroupDefinition>
CreatePermissionGroupDefinitions()
{
using (var scope = _serviceProvider.CreateScope())
{
//调用所有的 IPermissionDefinitionProvider 把
// PermissionGroupDefinition 保存到上下文里
var context = new PermissionDefinitionContext(scope.ServiceProvider);
var providers = Options
.DefinitionProviders
.Select(p => (scope.ServiceProvider.GetRequiredService(p)
as IPermissionDefinitionProvider)!)
.ToList();
foreach (var provider in providers)
{
provider.PreDefine(context);
}
foreach (var provider in providers)
{
provider.Define(context);
}
foreach (var provider in providers)
{
provider.PostDefine(context);
}
return context.Groups;
}
}
public Task<PermissionDefinition?> GetOrNullAsync(string name)
{
return Task.FromResult(PermissionDefinitions.GetOrDefault(name));
}
public virtual Task<IReadOnlyList<PermissionDefinition>> GetPermissionsAsync()
{
return Task.FromResult<IReadOnlyList<PermissionDefinition>>(
PermissionDefinitions.Values.ToImmutableList()
);
}
public Task<IReadOnlyList<PermissionGroupDefinition>> GetGroupsAsync()
{
return Task.FromResult<IReadOnlyList<PermissionGroupDefinition>>(
PermissionGroupDefinitions.Values.ToImmutableList()
);
}
}
PermissionDefinitionManager
通过 IStaticPermissionDefinitionStore , 获取代码定义的 IPermissionDefinition 通过 IDynamicPermissionDefinitionStore,获取数据库里别外定义的 IPermissionDefinition
namespace Volo.Abp.Authorization.Permissions;
public class PermissionDefinitionManager : IPermissionDefinitionManager,
ITransientDependency
{
private readonly IStaticPermissionDefinitionStore _staticStore;
//保存在 IPermissionGroupDefinitionRecordRepository ,
// IPermissionDefinitionRecordRepository 仓库里的
private readonly IDynamicPermissionDefinitionStore _dynamicStore;
public PermissionDefinitionManager(
IStaticPermissionDefinitionStore staticStore,
IDynamicPermissionDefinitionStore dynamicStore)
{
_staticStore = staticStore;
_dynamicStore = dynamicStore;
}
public virtual async Task<PermissionDefinition> GetAsync(string name)
{
var permission = await GetOrNullAsync(name);
if (permission == null)
{
throw new AbpException("Undefined permission: " + name);
}
return permission;
}
public virtual async Task<PermissionDefinition?> GetOrNullAsync(string name)
{
Check.NotNull(name, nameof(name));
//在代码里的获取不到就到数据库去获取
return await _staticStore.GetOrNullAsync(name) ??
await _dynamicStore.GetOrNullAsync(name);
}
public virtual async Task<IReadOnlyList<PermissionDefinition>> GetPermissionsAsync()
{
var staticPermissions = await _staticStore.GetPermissionsAsync();
var staticPermissionNames = staticPermissions
.Select(p => p.Name)
.ToImmutableHashSet();
var dynamicPermissions = await _dynamicStore.GetPermissionsAsync();
/* We prefer static permissions over dynamics */
//合并代码里定义的静态 Permissions 和数据库的动态 Permissions,名字重复的以代码里的为准
return staticPermissions.Concat(
dynamicPermissions.Where(d => !staticPermissionNames.Contains(d.Name))
).ToImmutableList();
}
public async Task<IReadOnlyList<PermissionGroupDefinition>> GetGroupsAsync()
{
var staticGroups = await _staticStore.GetGroupsAsync();
var staticGroupNames = staticGroups
.Select(p => p.Name)
.ToImmutableHashSet();
var dynamicGroups = await _dynamicStore.GetGroupsAsync();
/* We prefer static groups over dynamics */
return staticGroups.Concat(
dynamicGroups.Where(d => !staticGroupNames.Contains(d.Name))
).ToImmutableList();
}
}
静态的权限同步到数据库
在应用程序启动的时候会把静态的权限同步到数据库,并且会 redis 进行缓存是否同步过,如果 redis 保存了同步的 hash ,数据就不会进数据库
[DependsOn(typeof(AbpAuthorizationModule))]
[DependsOn(typeof(AbpDddDomainModule))]
[DependsOn(typeof(AbpPermissionManagementDomainSharedModule))]
[DependsOn(typeof(AbpCachingModule))]
[DependsOn(typeof(AbpJsonModule))]
public class AbpPermissionManagementDomainModule : AbpModule
{
private readonly CancellationTokenSource _cancellationTokenSource = new();
private Task _initializeDynamicPermissionsTask;
public override void ConfigureServices(ServiceConfigurationContext context)
{
if (context.Services.IsDataMigrationEnvironment())
{
Configure<PermissionManagementOptions>(options =>
{
options.SaveStaticPermissionsToDatabase = false;
//缓存
options.IsDynamicPermissionStoreEnabled = false;
});
}
}
public override void OnApplicationInitialization(ApplicationInitializationContext
context)
{
AsyncHelper.RunSync(() => OnApplicationInitializationAsync(context));
}
public override Task OnApplicationInitializationAsync(ApplicationInitializationContext
context)
{
InitializeDynamicPermissions(context);
return Task.CompletedTask;
}
public override Task OnApplicationShutdownAsync(ApplicationShutdownContext context)
{
_cancellationTokenSource.Cancel();
return Task.CompletedTask;
}
public Task GetInitializeDynamicPermissionsTask()
{
return _initializeDynamicPermissionsTask ?? Task.CompletedTask;
}
private void InitializeDynamicPermissions(ApplicationInitializationContext context)
{
var options = context
.ServiceProvider
.GetRequiredService<IOptions<PermissionManagementOptions>>()
.Value;
if (!options.SaveStaticPermissionsToDatabase &&
!options.IsDynamicPermissionStoreEnabled)
{
return;
}
var rootServiceProvider = context.ServiceProvider.
GetRequiredService<IRootServiceProvider>();
_initializeDynamicPermissionsTask = Task.Run(async () =>
{
using var scope = rootServiceProvider.CreateScope();
var applicationLifetime = scope.ServiceProvider.
GetService<IHostApplicationLifetime>();
var cancellationTokenProvider = scope.ServiceProvider.
GetRequiredService<ICancellationTokenProvider>();
var cancellationToken =
applicationLifetime?.ApplicationStopping ?? _cancellationTokenSource.Token;
try
{
using (cancellationTokenProvider.Use(cancellationToken))
{
if (cancellationTokenProvider.Token.IsCancellationRequested)
{
return;
}
await SaveStaticPermissionsToDatabaseAsync(
options, scope, cancellationTokenProvider);
if (cancellationTokenProvider.Token.IsCancellationRequested)
{
return;
}
await PreCacheDynamicPermissionsAsync(options, scope);
}
}
// ReSharper disable once EmptyGeneralCatchClause (
//No need to log since it is logged above)
catch { }
});
}
private async static Task SaveStaticPermissionsToDatabaseAsync(
PermissionManagementOptions options,
IServiceScope scope,
ICancellationTokenProvider cancellationTokenProvider)
{
if (!options.SaveStaticPermissionsToDatabase)
{
return;
}
await Policy
.Handle<Exception>()
.WaitAndRetryAsync(
8,
retryAttempt => TimeSpan.FromSeconds(
RandomHelper.GetRandom(
(int)Math.Pow(2, retryAttempt) * 8,
(int)Math.Pow(2, retryAttempt) * 12)
)
)
.ExecuteAsync(async _ =>
{
try
{
// ReSharper disable once AccessToDisposedClosure
await scope
.ServiceProvider
.GetRequiredService<IStaticPermissionSaver>()
.SaveAsync();
}
catch (Exception ex)
{
// ReSharper disable once AccessToDisposedClosure
scope.ServiceProvider
.GetService<ILogger<AbpPermissionManagementDomainModule>>()?
.LogException(ex);
throw; // Polly will catch it
}
}, cancellationTokenProvider.Token);
}
private async static Task PreCacheDynamicPermissionsAsync(
PermissionManagementOptions options, IServiceScope scope)
{
if (!options.IsDynamicPermissionStoreEnabled)
{
return;
}
try
{
// Pre-cache permissions, so first request doesn't wait
await scope
.ServiceProvider
.GetRequiredService<IDynamicPermissionDefinitionStore>()
.GetGroupsAsync();
}
catch (Exception ex)
{
// ReSharper disable once AccessToDisposedClosure
scope
.ServiceProvider
.GetService<ILogger<AbpPermissionManagementDomainModule>>()?
.LogException(ex);
throw; // It will be cached in InitializeDynamicPermissions
}
}
}
PermissionValueProvider 用来验证权限的
public interface IPermissionValueProvider
{
string Name { get; }
//TODO: Rename to GetResult? (CheckAsync throws exception by naming convention)
Task<PermissionGrantResult> CheckAsync(PermissionValueCheckContext context);
Task<MultiplePermissionGrantResult> CheckAsync(PermissionValuesCheckContext context);
}
public abstract class PermissionValueProvider : IPermissionValueProvider,
ITransientDependency
{
public abstract string Name { get; }
protected IPermissionStore PermissionStore { get; }
protected PermissionValueProvider(IPermissionStore permissionStore)
{
PermissionStore = permissionStore;
}
public abstract Task<PermissionGrantResult> CheckAsync(
PermissionValueCheckContext context);
public abstract Task<MultiplePermissionGrantResult> CheckAsync(
PermissionValuesCheckContext context);
}
abp 默认的实现类
授权检查就是检查 PermissionDefinition 的 name 和 providerName(U R,C,及客户自定义) 的及 providerKey (U 就是用户 userId,R 就是用户 Role,C 就是用户 ClientId ) 是否在数据库 IPermissionGrantRepository 存在,已经判断过的 abp 会进行缓存。
namespace Volo.Abp.Authorization.Permissions;
public class PermissionValueCheckContext
{
[NotNull]
public PermissionDefinition Permission { get; }
public ClaimsPrincipal? Principal { get; }
public PermissionValueCheckContext(
[NotNull] PermissionDefinition permission,
ClaimsPrincipal? principal)
{
Check.NotNull(permission, nameof(permission));
Permission = permission;
Principal = principal;
}
}
Abp 提供了三种权限值实现,分别是 Client、Role、User
- ClientPermissionValueProvider : 从当前声明中拿到当前客户端并检查客户端是否具有指定的权 限. 这在没有当前登录用户的客户端交互特别有用. 客户端声明由 AbpClaimTypes.ClientId 静态 属性定义
- RolePermissionValueProvider : 从当前的声明中拿到授予当前用户的角色集合并且判断角色是否 具有指定的权限. 角色声明由 AbpClaimTypes.Role 静态属性定义
- UserPermissionValueProvider : 从当前的声明中拿到当前用户 ID 并检查用户授权. 用户声明由 AbpClaimTypes.UserId 静态属性定义
- 用户也可以定义自己的 PermissionValueProvider,用于自定义权限检查
PermissionValueProvider 的 CheckAsync 应该返回下面三个值之一:
- PermissionGrantResult.Granted 授予用户权限,如果没有其他的授权值提供程序返回 Prohibited, 那么最后会返回 Granted.
- PermissionGrantResult.Prohibited 禁止授权用户,任何一个授权值提供程序返回了 Prohibited, 那么其他的提供程序返回的值都不再重要.
- PermissionGrantResult.Undefined 代表当前无法确定是否授予或禁止权限, 返回 UnDefined 由其 他权限值提供程序检查权限.
UserPermissionValueProvider 用户授权检查
public class UserPermissionValueProvider : PermissionValueProvider
{
// U 代表用户
public const string ProviderName = "U";
public override string Name => ProviderName;
//通过 IPermissionStore 获取所有已经被使用的权限 IPermissionGrantRepository
public UserPermissionValueProvider(IPermissionStore permissionStore)
: base(permissionStore)
{
}
//只有一个权限
public override async Task<PermissionGrantResult> CheckAsync(
PermissionValueCheckContext context)
{
// use 授权第一步获取 Principal 的 AbpClaimTypes.UserId
var userId = context.Principal?.FindFirst(AbpClaimTypes.UserId)?.Value;
if (userId == null)
{
return PermissionGrantResult.Undefined;
}
//在已经授权的数据库表里找到匹配的
return await PermissionStore.IsGrantedAsync(context.Permission.Name, Name, userId)
? PermissionGrantResult.Granted
: PermissionGrantResult.Undefined;
}
//有多个权限,只要全部授权成功才成功
public override async Task<MultiplePermissionGrantResult> CheckAsync(
PermissionValuesCheckContext context)
{
var permissionNames = context.Permissions.Select(x => x.Name).Distinct().ToArray();
Check.NotNullOrEmpty(permissionNames, nameof(permissionNames));
var userId = context.Principal?.FindFirst(AbpClaimTypes.UserId)?.Value;
if (userId == null)
{
return new MultiplePermissionGrantResult(permissionNames);
}
return await PermissionStore.IsGrantedAsync(permissionNames, Name, userId);
}
}
RolePermissionValueProvider 角色授权检查
public class RolePermissionValueProvider : PermissionValueProvider
{
public const string ProviderName = "R";
public override string Name => ProviderName;
public RolePermissionValueProvider(IPermissionStore permissionStore)
: base(permissionStore)
{
}
//只有一个权限,只要用户有一个权限被授权了就通过
public override async Task<PermissionGrantResult> CheckAsync(
PermissionValueCheckContext context)
{
var roles = context.Principal?.FindAll(AbpClaimTypes.Role).
Select(c => c.Value).ToArray();
if (roles == null || !roles.Any())
{
return PermissionGrantResult.Undefined;
}
//只要一个 PermissionDefinition,只要存在一条符合提交的就认证成功
foreach (var role in roles.Distinct())
{
if (await PermissionStore.IsGrantedAsync(context.Permission.Name, Name, role))
{
return PermissionGrantResult.Granted;
}
}
return PermissionGrantResult.Undefined;
}
// 有多个权限,只要全部授权成功才成功
public override async Task<MultiplePermissionGrantResult> CheckAsync(
PermissionValuesCheckContext context)
{
var permissionNames = context.Permissions.Select(x => x.Name).Distinct().ToList();
Check.NotNullOrEmpty(permissionNames, nameof(permissionNames));
var result = new MultiplePermissionGrantResult(permissionNames.ToArray());
var roles = context.Principal?.FindAll(AbpClaimTypes.Role).Select(
c => c.Value).ToArray();
if (roles == null || !roles.Any())
{
return result;
}
foreach (var role in roles.Distinct())
{
//每个角色
var multipleResult = await PermissionStore.IsGrantedAsync(
permissionNames.ToArray(), Name, role);
foreach (var grantResult in multipleResult.Result.Where(grantResult =>
result.Result.ContainsKey(grantResult.Key) &&
result.Result[grantResult.Key] == PermissionGrantResult.Undefined &&
grantResult.Value != PermissionGrantResult.Undefined))
{
result.Result[grantResult.Key] = grantResult.Value;
permissionNames.RemoveAll(x => x == grantResult.Key);
}
if (result.AllGranted || result.AllProhibited)
{
break;
}
if (permissionNames.IsNullOrEmpty())
{
break;
}
}
return result;
}
}
ClientPermissionValueProvider 授权检查
public class ClientPermissionValueProvider : PermissionValueProvider
{
public const string ProviderName = "C";
public override string Name => ProviderName;
protected ICurrentTenant CurrentTenant { get; }
public ClientPermissionValueProvider(IPermissionStore permissionStore,
ICurrentTenant currentTenant)
: base(permissionStore)
{
CurrentTenant = currentTenant;
}
public override async Task<PermissionGrantResult> CheckAsync(
PermissionValueCheckContext context)
{
var clientId = context.Principal?.FindFirst(AbpClaimTypes.ClientId)?.Value;
if (clientId == null)
{
return PermissionGrantResult.Undefined;
}
//只对特定的用户而言,不是租户
using (CurrentTenant.Change(null))
{
return await PermissionStore.IsGrantedAsync(
context.Permission.Name, Name, clientId)
? PermissionGrantResult.Granted
: PermissionGrantResult.Undefined;
}
}
//多个权限检查
public override async Task<MultiplePermissionGrantResult> CheckAsync(
PermissionValuesCheckContext context)
{
var permissionNames = context.Permissions.Select(x => x.Name).Distinct().ToArray();
Check.NotNullOrEmpty(permissionNames, nameof(permissionNames));
var clientId = context.Principal?.FindFirst(AbpClaimTypes.ClientId)?.Value;
if (clientId == null)
{
return new MultiplePermissionGrantResult(permissionNames); ;
}
using (CurrentTenant.Change(null))
{
return await PermissionStore.IsGrantedAsync(permissionNames, Name, clientId);
}
}
}
IPermissionValueProviderManager
namespace Volo.Abp.Authorization.Permissions;
public interface IPermissionValueProviderManager
{
IReadOnlyList<IPermissionValueProvider> ValueProviders { get; }
}
注册的所有 PermissionValueProvider 通过 PermissionValueProviderManager 发现
public class PermissionValueProviderManager : IPermissionValueProviderManager,
ISingletonDependency
{
public IReadOnlyList<IPermissionValueProvider> ValueProviders => _lazyProviders.Value;
private readonly Lazy<List<IPermissionValueProvider>> _lazyProviders;
protected AbpPermissionOptions Options { get; }
// AbpPermissionOptions 里获取到
public PermissionValueProviderManager(
IServiceProvider serviceProvider,
IOptions<AbpPermissionOptions> options)
{
Options = options.Value;
_lazyProviders = new Lazy<List<IPermissionValueProvider>>(
() => Options
.ValueProviders
.Select(c => serviceProvider.GetRequiredService(c)
as IPermissionValueProvider)
.ToList()!,
true
);
}
}
IPermissionChecker
public interface IPermissionChecker 定义的各种 IPermissionDefinition 及 IPermissionValueProvider 最后被 IPermissionChecker 统一使用进行授权判断
namespace Volo.Abp.Authorization.Permissions;
public interface IPermissionChecker
{
Task<bool> IsGrantedAsync([NotNull] string name);
Task<bool> IsGrantedAsync(ClaimsPrincipal? claimsPrincipal, [NotNull] string name);
Task<MultiplePermissionGrantResult> IsGrantedAsync([NotNull] string[] names);
Task<MultiplePermissionGrantResult> IsGrantedAsync(ClaimsPrincipal?
claimsPrincipal, [NotNull] string[] names);
}
AlwaysAllowPermissionChecker 允许直接通过,在测试环境使用
PermissionChecker
public class PermissionChecker : IPermissionChecker, ITransientDependency
{
protected IPermissionDefinitionManager PermissionDefinitionManager { get; }
protected ICurrentPrincipalAccessor PrincipalAccessor { get; }
protected ICurrentTenant CurrentTenant { get; }
protected IPermissionValueProviderManager PermissionValueProviderManager { get; }
protected ISimpleStateCheckerManager<PermissionDefinition> StateCheckerManager { get; }
public PermissionChecker(
ICurrentPrincipalAccessor principalAccessor,
IPermissionDefinitionManager permissionDefinitionManager,
ICurrentTenant currentTenant,
IPermissionValueProviderManager permissionValueProviderManager,
ISimpleStateCheckerManager<PermissionDefinition> stateCheckerManager)
{
PrincipalAccessor = principalAccessor;
PermissionDefinitionManager = permissionDefinitionManager;
CurrentTenant = currentTenant;
PermissionValueProviderManager = permissionValueProviderManager;
StateCheckerManager = stateCheckerManager;
}
public virtual async Task<bool> IsGrantedAsync(string name)
{
return await IsGrantedAsync(PrincipalAccessor.Principal, name);
}
public virtual async Task<bool> IsGrantedAsync(
ClaimsPrincipal? claimsPrincipal,
string name)
{
Check.NotNull(name, nameof(name));
var permission = await PermissionDefinitionManager.GetOrNullAsync(name);
if (permission == null)
{
return false;
}
if (!permission.IsEnabled)
{
return false;
}
if (!await StateCheckerManager.IsEnabledAsync(permission))
{
return false;
}
var multiTenancySide = claimsPrincipal?.GetMultiTenancySide()
?? CurrentTenant.GetMultiTenancySide();
if (!permission.MultiTenancySide.HasFlag(multiTenancySide))
{
return false;
}
var isGranted = false;
var context = new PermissionValueCheckContext(permission, claimsPrincipal);
foreach (var provider in PermissionValueProviderManager.ValueProviders)
{
if (context.Permission.Providers.Any() &&
!context.Permission.Providers.Contains(provider.Name))
{
continue;
}
var result = await provider.CheckAsync(context);
if (result == PermissionGrantResult.Granted)
{
isGranted = true;
}
else if (result == PermissionGrantResult.Prohibited)
{
return false;
}
}
return isGranted;
}
public async Task<MultiplePermissionGrantResult> IsGrantedAsync(string[] names)
{
return await IsGrantedAsync(PrincipalAccessor.Principal, names);
}
public async Task<MultiplePermissionGrantResult> IsGrantedAsync(ClaimsPrincipal?
claimsPrincipal, string[] names)
{
Check.NotNull(names, nameof(names));
var result = new MultiplePermissionGrantResult();
if (!names.Any())
{
return result;
}
var multiTenancySide = claimsPrincipal?.GetMultiTenancySide() ??
CurrentTenant.GetMultiTenancySide();
var permissionDefinitions = new List<PermissionDefinition>();
foreach (var name in names)
{
var permission = await PermissionDefinitionManager.GetOrNullAsync(name);
if (permission == null)
{
result.Result.Add(name, PermissionGrantResult.Prohibited);
continue;
}
result.Result.Add(name, PermissionGrantResult.Undefined);
if (permission.IsEnabled &&
await StateCheckerManager.IsEnabledAsync(permission) &&
permission.MultiTenancySide.HasFlag(multiTenancySide))
{
permissionDefinitions.Add(permission);
}
}
foreach (var provider in PermissionValueProviderManager.ValueProviders)
{
var permissions = permissionDefinitions
.Where(x => !x.Providers.Any() || x.Providers.Contains(provider.Name))
.ToList();
if (permissions.IsNullOrEmpty())
{
continue;
}
var context = new PermissionValuesCheckContext(
permissions,
claimsPrincipal);
var multipleResult = await provider.CheckAsync(context);
foreach (var grantResult in multipleResult.Result.Where(grantResult =>
result.Result.ContainsKey(grantResult.Key) &&
result.Result[grantResult.Key] == PermissionGrantResult.Undefined &&
grantResult.Value != PermissionGrantResult.Undefined))
{
result.Result[grantResult.Key] = grantResult.Value;
permissionDefinitions.RemoveAll(x => x.Name == grantResult.Key);
}
if (result.AllGranted || result.AllProhibited)
{
break;
}
}
return result;
}
}
RemotePermissionChecker 远程服务验证使用
public class RemotePermissionChecker : IPermissionChecker, ITransientDependency
{
protected ICachedApplicationConfigurationClient ConfigurationClient { get; }
public RemotePermissionChecker(ICachedApplicationConfigurationClient
configurationClient)
{
ConfigurationClient = configurationClient;
}
public async Task<bool> IsGrantedAsync(string name)
{
var configuration = await ConfigurationClient.GetAsync();
return configuration.Auth.GrantedPolicies.ContainsKey(name);
}
public async Task<bool> IsGrantedAsync(ClaimsPrincipal? claimsPrincipal, string name)
{
/* This provider always works for the current principal. */
return await IsGrantedAsync(name);
}
public async Task<MultiplePermissionGrantResult> IsGrantedAsync(string[] names)
{
var result = new MultiplePermissionGrantResult();
var configuration = await ConfigurationClient.GetAsync();
foreach (var name in names)
{
result.Result.Add(name, configuration.Auth.GrantedPolicies.ContainsKey(name) ?
PermissionGrantResult.Granted :
PermissionGrantResult.Undefined);
}
return result;
}
public async Task<MultiplePermissionGrantResult> IsGrantedAsync(
ClaimsPrincipal? claimsPrincipal, string[] names)
{
/* This provider always works for the current principal. */
return await IsGrantedAsync(names);
}
}
PermissionRequirement 和 asp.net core 的 policy 结合
这句是关键 foreach (var req in context.Requirements.OfType<TRequirement>())
namespace Microsoft.AspNetCore.Authorization;
public abstract class AuthorizationHandler<TRequirement> : IAuthorizationHandler
where TRequirement : IAuthorizationRequirement
{
//
public virtual async Task HandleAsync(AuthorizationHandlerContext context)
{
// 此类 AuthorizationHandler 是和 TRequirement 进行绑定的
// 需要通过 context.Requirements.OfType 获取到此类能处理的 TRequirement
foreach (var req in context.Requirements.OfType<TRequirement>())
{
await HandleRequirementAsync(context, req).ConfigureAwait(false);
}
}
//用户实现业务逻辑
protected abstract Task HandleRequirementAsync(AuthorizationHandlerContext context,
TRequirement requirement);
}
实现 IAuthorizationRequirement
public class PermissionRequirement : IAuthorizationRequirement
{
public string PermissionName { get; }
public PermissionRequirement([NotNull] string permissionName)
{
Check.NotNull(permissionName, nameof(permissionName));
PermissionName = permissionName;
}
public override string ToString()
{
return $"PermissionRequirement: {PermissionName}";
}
}
// PermissionRequirement 处理类 通过 注入 IPermissionChecker 进行验证
// IPermissionChecker 完成正在的验证工作
public class PermissionRequirementHandler : AuthorizationHandler<PermissionRequirement>
{
private readonly IPermissionChecker _permissionChecker;
public PermissionRequirementHandler(IPermissionChecker permissionChecker)
{
_permissionChecker = permissionChecker;
}
protected override async Task HandleRequirementAsync(
AuthorizationHandlerContext context,
PermissionRequirement requirement)
{
if (await _permissionChecker.IsGrantedAsync(context.User, requirement.PermissionName))
{
context.Succeed(requirement);
}
}
}
public class PermissionsRequirement : IAuthorizationRequirement
{
public string[] PermissionNames { get; }
public bool RequiresAll { get; }
public PermissionsRequirement([NotNull] string[] permissionNames, bool requiresAll)
{
Check.NotNull(permissionNames, nameof(permissionNames));
PermissionNames = permissionNames;
RequiresAll = requiresAll;
}
public override string ToString()
{
return $"PermissionsRequirement: {string.Join(", ", PermissionNames)}";
}
}
// PermissionRequirements 处理类
public class PermissionsRequirementHandler : AuthorizationHandler<PermissionsRequirement>
{
private readonly IPermissionChecker _permissionChecker;
public PermissionsRequirementHandler(IPermissionChecker permissionChecker)
{
_permissionChecker = permissionChecker;
}
protected override async Task HandleRequirementAsync(
AuthorizationHandlerContext context,
PermissionsRequirement requirement)
{
var multiplePermissionGrantResult = await _permissionChecker.IsGrantedAsync(
context.User, requirement.PermissionNames);
if (requirement.RequiresAll ?
multiplePermissionGrantResult.AllGranted :
multiplePermissionGrantResult.Result.Any(
x => x.Value == PermissionGrantResult.Granted))
{
context.Succeed(requirement);
}
}
}
asp.net core 为 role 授权 实现的 RolesAuthorizationRequirement 及 handler
asp.net core role 授权 也是转换为 policy 授权
RolesAuthorizationRequirement 不需要注入 DI 因为它自己就是 handler
namespace Microsoft.AspNetCore.Authorization.Infrastructure;
授权 attribute 里赋值的 role 最终会转变为 RolesAuthorizationRequirement,此类同时也实现了 AuthorizationHandler
public class RolesAuthorizationRequirement :
AuthorizationHandler<RolesAuthorizationRequirement>, IAuthorizationRequirement
{
public RolesAuthorizationRequirement(IEnumerable<string> allowedRoles)
{
if (allowedRoles == null)
{
throw new ArgumentNullException(nameof(allowedRoles));
}
if (!allowedRoles.Any())
{
throw new InvalidOperationException(
Resources.Exception_RoleRequirementEmpty);
}
AllowedRoles = allowedRoles;
}
public IEnumerable<string> AllowedRoles { get; }
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context, RolesAuthorizationRequirement requirement)
{
if (context.User != null)
{
bool found = false;
if (requirement.AllowedRoles == null || !requirement.AllowedRoles.Any())
{
// Review: What do we want to do here? No roles requested is auto success?
}
else
{
found = requirement.AllowedRoles.Any(r => context.User.IsInRole(r));
}
// 只要当前认证的用户的角色有一个在允许的角色里,就算认证成功
// 允许的角色来自 授权 attribute 上的 Roles 数据
if (found)
{
context.Succeed(requirement);
}
}
return Task.CompletedTask;
}
public override string ToString()
{
var roles = $"User.IsInRole must be true for one of the following roles:
({string.Join("|", AllowedRoles)})";
return $"{nameof(RolesAuthorizationRequirement)}:{roles}";
}
}
asp.net core claim 授权 也是转换为 policy 授权
ClaimsAuthorizationRequirement 不需要注入 DI 因为它自己就是 handler
public class ClaimsAuthorizationRequirement :
AuthorizationHandler<ClaimsAuthorizationRequirement>, IAuthorizationRequirement
{
public ClaimsAuthorizationRequirement(string claimType,
IEnumerable<string>? allowedValues)
{
if (claimType == null)
{
throw new ArgumentNullException(nameof(claimType));
}
ClaimType = claimType;
AllowedValues = allowedValues;
}
public string ClaimType { get; }
public IEnumerable<string>? AllowedValues { get; }
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context, ClaimsAuthorizationRequirement requirement)
{
if (context.User != null)
{
var found = false;
//只判断 claim 类型有就可以
if (requirement.AllowedValues == null ||
!requirement.AllowedValues.Any())
{
found = context.User.Claims.Any(c =>
string.Equals(c.Type, requirement.ClaimType, StringComparison.OrdinalIgnoreCase));
}
else
{
//不但 claim 类型要有对,claim 的值也要符合
found = context.User.Claims.Any(c =>
string.Equals(c.Type, requirement.ClaimType, StringComparison.OrdinalIgnoreCase)
&& requirement.AllowedValues.Contains(c.Value, StringComparer.Ordinal));
}
if (found)
{
context.Succeed(requirement);
}
}
return Task.CompletedTask;
}
public override string ToString()
{
var value = (AllowedValues == null || !AllowedValues.Any())
? string.Empty
: $" and Claim.Value is one of the following values:
({string.Join("|", AllowedValues)})";
return $"{nameof(ClaimsAuthorizationRequirement)}:Claim.Type={ClaimType}{value}";
}
}
asp.net core user name 授权 也是转换为 policy 授权
namespace Microsoft.AspNetCore.Authorization.Infrastructure;
public class NameAuthorizationRequirement :
AuthorizationHandler<NameAuthorizationRequirement>, IAuthorizationRequirement
{
public NameAuthorizationRequirement(string requiredName)
{
if (requiredName == null)
{
throw new ArgumentNullException(nameof(requiredName));
}
RequiredName = requiredName;
}
public string RequiredName { get; }
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context, NameAuthorizationRequirement requirement)
{
if (context.User != null)
{
if (context.User.Identities.Any(i => string.Equals(
i.Name, requirement.RequiredName, StringComparison.Ordinal)))
{
context.Succeed(requirement);
}
}
return Task.CompletedTask;
}
public override string ToString()
{
return $"{nameof(NameAuthorizationRequirement)}:
Requires a user identity with Name equal to {RequiredName}";
}
}
PassThroughAuthorizationHandler 处理通过配置生成的策略的,requirement 和 handler 是一类的
IAuthorizationRequirement 的实现类要加入 DI,按照 asp.net core 的约定,因为授权服务会在 DI 获取所有的 handler,除过 IAuthorizationRequirement 自己本身也是实现类的这种
namespace Microsoft.AspNetCore.Authorization.Infrastructure
{
public class PassThroughAuthorizationHandler : IAuthorizationHandler
{
private readonly AuthorizationOptions _options;
public PassThroughAuthorizationHandler()
: this(Microsoft.Extensions.Options.Options.
Create<AuthorizationOptions>(new AuthorizationOptions()))
{
}
public PassThroughAuthorizationHandler(IOptions<AuthorizationOptions> options) =>
this._options = options.Value;
public async Task HandleAsync(AuthorizationHandlerContext context)
{
// Requirement 找出本身就是 handler
foreach (IAuthorizationHandler authorizationHandler in
context.Requirements.OfType<IAuthorizationHandler>())
{
await authorizationHandler.HandleAsync(context).ConfigureAwait(false);
if (!this._options.InvokeHandlersAfterFailure)
{
if (context.HasFailed)
break;
}
}
}
}
}
asp.net core AuthorizationPolicy
AuthorizationPolicy 保存所有的 IAuthorizationRequirement 及 AuthenticationSchemes
public class AuthorizationPolicy
{
public AuthorizationPolicy(IEnumerable<IAuthorizationRequirement> requirements,
IEnumerable<string> authenticationSchemes)
{
if (requirements == null)
{
throw new ArgumentNullException(nameof(requirements));
}
if (authenticationSchemes == null)
{
throw new ArgumentNullException(nameof(authenticationSchemes));
}
if (!requirements.Any())
{
throw new InvalidOperationException(Resources.Exception_AuthorizationPolicyEmpty);
}
Requirements = new List<IAuthorizationRequirement>(requirements).AsReadOnly();
AuthenticationSchemes = new List<string>(authenticationSchemes).AsReadOnly();
}
public IReadOnlyList<IAuthorizationRequirement> Requirements { get; }
public IReadOnlyList<string> AuthenticationSchemes { get; }
public static AuthorizationPolicy Combine(params AuthorizationPolicy[] policies)
{
if (policies == null)
{
throw new ArgumentNullException(nameof(policies));
}
return Combine((IEnumerable<AuthorizationPolicy>)policies);
}
//具有多个 AuthorizationPolicy 的功能
public static AuthorizationPolicy Combine(IEnumerable<AuthorizationPolicy> policies)
{
if (policies == null)
{
throw new ArgumentNullException(nameof(policies));
}
//把多个 AuthorizationPolicy 进行合并并返回一个新的 AuthorizationPolicy
var builder = new AuthorizationPolicyBuilder();
foreach (var policy in policies)
{
builder.Combine(policy);
}
return builder.Build();
}
public static Task<AuthorizationPolicy?> CombineAsync(
IAuthorizationPolicyProvider policyProvider,
IEnumerable<IAuthorizeData> authorizeData) => CombineAsync(
policyProvider, authorizeData,
Enumerable.Empty<AuthorizationPolicy>());
//把 授权 attribute 里的 policy 或 rule 合并进 AuthorizationPolicy
public static async Task<AuthorizationPolicy?> CombineAsync(
IAuthorizationPolicyProvider policyProvider,
IEnumerable<IAuthorizeData> authorizeData,
IEnumerable<AuthorizationPolicy> policies)
{
if (policyProvider == null)
{
throw new ArgumentNullException(nameof(policyProvider));
}
if (authorizeData == null)
{
throw new ArgumentNullException(nameof(authorizeData));
}
var anyPolicies = policies.Any();
// Avoid allocating enumerator if the data is known to be empty
var skipEnumeratingData = false;
if (authorizeData is IList<IAuthorizeData> dataList)
{
skipEnumeratingData = dataList.Count == 0;
}
// build 构建 AuthorizationPolicy
AuthorizationPolicyBuilder? policyBuilder = null;
//有授权 attribute
if (!skipEnumeratingData)
{
foreach (var authorizeDatum in authorizeData)
{
if (policyBuilder == null)
{
policyBuilder = new AuthorizationPolicyBuilder();
}
var useDefaultPolicy = !(anyPolicies);
if (!string.IsNullOrWhiteSpace(authorizeDatum.Policy))
{
var policy = await policyProvider.
GetPolicyAsync(authorizeDatum.Policy).ConfigureAwait(false);
if (policy == null)
{
throw new InvalidOperationException(
Resources.FormatException_AuthorizationPolicyNotFound(authorizeDatum.Policy));
}
policyBuilder.Combine(policy);
useDefaultPolicy = false;
}
//角色在授权 attribute里获取设置的角色
var rolesSplit = authorizeDatum.Roles?.Split(',');
if (rolesSplit?.Length > 0)
{
var trimmedRolesSplit = rolesSplit.Where(r =>
!string.IsNullOrWhiteSpace(r)).Select(r => r.Trim());
// 添加 role permission
policyBuilder.RequireRole(trimmedRolesSplit);
useDefaultPolicy = false;
}
var authTypesSplit = authorizeDatum.AuthenticationSchemes?.Split(',');
if (authTypesSplit?.Length > 0)
{
foreach (var authType in authTypesSplit)
{
if (!string.IsNullOrWhiteSpace(authType))
{
policyBuilder.AuthenticationSchemes.Add(authType.Trim());
}
}
}
if (useDefaultPolicy)
{
policyBuilder.Combine(await policyProvider.GetDefaultPolicyAsync().
ConfigureAwait(false));
}
}
}
if (anyPolicies)
{
policyBuilder ??= new();
foreach (var policy in policies)
{
policyBuilder.Combine(policy);
}
}
// If we have no policy by now, use the fallback policy if we have one
if (policyBuilder == null)
{
var fallbackPolicy = await policyProvider.GetFallbackPolicyAsync().
ConfigureAwait(false);
if (fallbackPolicy != null)
{
return fallbackPolicy;
}
}
return policyBuilder?.Build();
}
}
通过 AuthorizationPolicyBuilder 构建 Authorization
namespace Microsoft.AspNetCore.Authorization;
public class AuthorizationPolicyBuilder
{
public AuthorizationPolicyBuilder(params string[] authenticationSchemes)
{
AddAuthenticationSchemes(authenticationSchemes);
}
public AuthorizationPolicyBuilder(AuthorizationPolicy policy)
{
Combine(policy);
}
public IList<IAuthorizationRequirement> Requirements { get; set; } =
new List<IAuthorizationRequirement>();
public IList<string> AuthenticationSchemes { get; set; } = new List<string>();
public AuthorizationPolicyBuilder AddAuthenticationSchemes(params string[] schemes)
{
foreach (var authType in schemes)
{
AuthenticationSchemes.Add(authType);
}
return this;
}
public AuthorizationPolicyBuilder AddRequirements(params IAuthorizationRequirement[]
requirements)
{
foreach (var req in requirements)
{
Requirements.Add(req);
}
return this;
}
public AuthorizationPolicyBuilder Combine(AuthorizationPolicy policy)
{
if (policy == null)
{
throw new ArgumentNullException(nameof(policy));
}
AddAuthenticationSchemes(policy.AuthenticationSchemes.ToArray());
AddRequirements(policy.Requirements.ToArray());
return this;
}
public AuthorizationPolicyBuilder RequireClaim(string claimType,
params string[] allowedValues)
{
if (claimType == null)
{
throw new ArgumentNullException(nameof(claimType));
}
return RequireClaim(claimType, (IEnumerable<string>)allowedValues);
}
public AuthorizationPolicyBuilder RequireClaim(string claimType,
IEnumerable<string> allowedValues)
{
if (claimType == null)
{
throw new ArgumentNullException(nameof(claimType));
}
Requirements.Add(new ClaimsAuthorizationRequirement(claimType, allowedValues));
return this;
}
public AuthorizationPolicyBuilder RequireClaim(string claimType)
{
if (claimType == null)
{
throw new ArgumentNullException(nameof(claimType));
}
Requirements.Add(new ClaimsAuthorizationRequirement(claimType,
allowedValues: null));
return this;
}
public AuthorizationPolicyBuilder RequireRole(params string[] roles)
{
if (roles == null)
{
throw new ArgumentNullException(nameof(roles));
}
return RequireRole((IEnumerable<string>)roles);
}
public AuthorizationPolicyBuilder RequireRole(IEnumerable<string> roles)
{
if (roles == null)
{
throw new ArgumentNullException(nameof(roles));
}
Requirements.Add(new RolesAuthorizationRequirement(roles));
return this;
}
public AuthorizationPolicyBuilder RequireUserName(string userName)
{
if (userName == null)
{
throw new ArgumentNullException(nameof(userName));
}
Requirements.Add(new NameAuthorizationRequirement(userName));
return this;
}
public AuthorizationPolicyBuilder RequireAuthenticatedUser()
{
Requirements.Add(new DenyAnonymousAuthorizationRequirement());
return this;
}
public AuthorizationPolicyBuilder RequireAssertion(
Func<AuthorizationHandlerContext, bool> handler)
{
if (handler == null)
{
throw new ArgumentNullException(nameof(handler));
}
Requirements.Add(new AssertionRequirement(handler));
return this;
}
public AuthorizationPolicyBuilder RequireAssertion
(Func<AuthorizationHandlerContext, Task<bool>> handler)
{
if (handler == null)
{
throw new ArgumentNullException(nameof(handler));
}
Requirements.Add(new AssertionRequirement(handler));
return this;
}
public AuthorizationPolicy Build()
{
return new AuthorizationPolicy(Requirements, AuthenticationSchemes.Distinct());
}
}
asp.net core AuthorizationOptions
asp.net core 提供的配置项目 AuthorizationOptions,在业务里就是通过它进行 policy 的配置,配
置的 policy,会保存进行 private Dictionary<string, AuthorizationPolicy>
public class AuthorizationOptions
{
//所有配置的 policy 会保存进 PolicyMap
private Dictionary<string, AuthorizationPolicy> PolicyMap { get; } =
new Dictionary<string, AuthorizationPolicy>(StringComparer.OrdinalIgnoreCase);
public bool InvokeHandlersAfterFailure { get; set; } = true;
//默认的授权是不允许匿名访问
public AuthorizationPolicy DefaultPolicy { get; set; } =
new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
//在没有配置任何 policy,情况下,最后能使用的 FallbackPolicy
public AuthorizationPolicy? FallbackPolicy { get; set; }
//用户通过此方法进行配置
public void AddPolicy(string name, AuthorizationPolicy policy)
{
if (name == null)
{
throw new ArgumentNullException(nameof(name));
}
if (policy == null)
{
throw new ArgumentNullException(nameof(policy));
}
PolicyMap[name] = policy;
}
//用户通过此方法进行配置
public void AddPolicy(string name, Action<AuthorizationPolicyBuilder> configurePolicy)
{
if (name == null)
{
throw new ArgumentNullException(nameof(name));
}
if (configurePolicy == null)
{
throw new ArgumentNullException(nameof(configurePolicy));
}
var policyBuilder = new AuthorizationPolicyBuilder();
configurePolicy(policyBuilder);
PolicyMap[name] = policyBuilder.Build();
}
//在 map 里获取指定名称的 policy
public AuthorizationPolicy? GetPolicy(string name)
{
if (name == null)
{
throw new ArgumentNullException(nameof(name));
}
if (PolicyMap.TryGetValue(name, out var value))
{
return value;
}
return null;
}
}
asp.net core IAuthorizationPolicyProvider
AuthorizationOptions 配置项提供的 AuthorizationPolicy 要被 IAuthorizationPolicyProvider 使 用
namespace Microsoft.AspNetCore.Authorization;
public interface IAuthorizationPolicyProvider
{
Task<AuthorizationPolicy?> GetPolicyAsync(string policyName);
Task<AuthorizationPolicy> GetDefaultPolicyAsync();
Task<AuthorizationPolicy?> GetFallbackPolicyAsync();
bool AllowsCachingPolicies => false;
}
//asp.net core 默认提供的 IAuthorizationPolicyProvider
//所提供的功能来自用户在 AuthorizationOptions 进行的配置
public class DefaultAuthorizationPolicyProvider : IAuthorizationPolicyProvider
{
private readonly AuthorizationOptions _options;
private Task<AuthorizationPolicy>? _cachedDefaultPolicy;
private Task<AuthorizationPolicy?>? _cachedFallbackPolicy;
public DefaultAuthorizationPolicyProvider(IOptions<AuthorizationOptions> options)
{
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
_options = options.Value;
}
public Task<AuthorizationPolicy> GetDefaultPolicyAsync()
{
if (_cachedDefaultPolicy == null ||
_cachedDefaultPolicy.Result != _options.DefaultPolicy)
{
_cachedDefaultPolicy = Task.FromResult(_options.DefaultPolicy);
}
return _cachedDefaultPolicy;
}
public Task<AuthorizationPolicy?> GetFallbackPolicyAsync()
{
if (_cachedFallbackPolicy == null ||
_cachedFallbackPolicy.Result != _options.FallbackPolicy)
{
_cachedFallbackPolicy = Task.FromResult(_options.FallbackPolicy);
}
return _cachedFallbackPolicy;
}
public virtual Task<AuthorizationPolicy?> GetPolicyAsync(string policyName)
{
return Task.FromResult(_options.GetPolicy(policyName));
}
public virtual bool AllowsCachingPolicies => GetType() ==
typeof(DefaultAuthorizationPolicyProvider);
}
AbpAuthorizationPolicyProvider 提供的 PolicyProvider
AbpAuthorizationPolicyProvider 继承 DefaultAuthorizationPolicyProvider asp.net 规定只能有 一个 IAuthorizationPolicyProvider ,起作用如果用户提供了 IAuthorizationPolicyProvider,默 认的就不起作用了
namespace Volo.Abp.Authorization;
public class AbpAuthorizationPolicyProvider :
DefaultAuthorizationPolicyProvider, IAbpAuthorizationPolicyProvider, ITransientDependency
{
private readonly AuthorizationOptions _options;
private readonly IPermissionDefinitionManager _permissionDefinitionManager;
// 继承 DefaultAuthorizationPolicyProvider
// asp.net core 原本配置的 policy 也可以起作用
public AbpAuthorizationPolicyProvider(
IOptions<AuthorizationOptions> options,
IPermissionDefinitionManager permissionDefinitionManager)
: base(options)
{
_permissionDefinitionManager = permissionDefinitionManager;
_options = options.Value;
}
public override async Task<AuthorizationPolicy?> GetPolicyAsync(string policyName)
{
//优先在 asp.net core 里获取 AuthorizationPolicy
// AuthorizationOptions 里配置的
var policy = await base.GetPolicyAsync(policyName);
if (policy != null)
{
return policy;
}
//获取不到再到 abp 里获取
// abp 优先获取代码里配置的,获取不到在到数据库里获取
/**
public virtual async Task<PermissionDefinition?> GetOrNullAsync(string name)
{
Check.NotNull(name, nameof(name));
return await _staticStore.GetOrNullAsync(name) ??
await _dynamicStore.GetOrNullAsync(name);
}
*/
var permission = await _permissionDefinitionManager.GetOrNullAsync(policyName);
if (permission != null)
{
// AuthorizationPolicyBuilder 把 PermissionRequirement 生成成 AuthorizationPolicy
//TODO: Optimize & Cache!
var policyBuilder = new AuthorizationPolicyBuilder(Array.Empty<string>());
policyBuilder.Requirements.Add(new PermissionRequirement(policyName));
//用 Requirements , 认证的 AuthenticationSchemes.Distinct() 生成 AuthorizationPolicy
return policyBuilder.Build();
}
return null;
}
// abp 提供的获取所有的是进行合并
public async Task<List<string>> GetPoliciesNamesAsync()
{
return _options.GetPoliciesNames()
.Union(
(await _permissionDefinitionManager
.GetPermissionsAsync())
.Select(p => p.Name)
)
.ToList();
}
}
asp.net core IAuthorizeData 保存 controller 或 action 上的 policy name
namespace Microsoft.AspNetCore.Authorization
{
public interface IAuthorizeData
{
string? Policy { get; set; }
string? Roles { get; set; }
string? AuthenticationSchemes { get; set; }
}
// asp.net core 提供的授权特性
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method,
AllowMultiple = true, Inherited = true)]
public class AuthorizeAttribute : Attribute, IAuthorizeData
{
public AuthorizeAttribute() { }
public AuthorizeAttribute(string policy)
{
Policy = policy;
}
public string? Policy { get; set; }
public string? Roles { get; set; }
public string? AuthenticationSchemes { get; set; }
}
asp.net core IAuthorizationService
public interface IAuthorizationService
{
Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user,
object? resource, IEnumerable<IAuthorizationRequirement> requirements);
Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user,
object? resource, string policyName);
}
public class DefaultAuthorizationService : IAuthorizationService
{
#nullable disable
private readonly AuthorizationOptions _options;
private readonly IAuthorizationHandlerContextFactory _contextFactory;
private readonly IAuthorizationHandlerProvider _handlers;
private readonly IAuthorizationEvaluator _evaluator;
private readonly IAuthorizationPolicyProvider _policyProvider;
private readonly ILogger _logger;
public DefaultAuthorizationService(
//policy 提供器 替换为 abp 提供的
IAuthorizationPolicyProvider policyProvider,
//授权处理器提供器,这个类获取 DI 容器里所有的 IAuthorizationHandler 实现对象
IAuthorizationHandlerProvider handlers,
ILogger<DefaultAuthorizationService> logger,
// 生成 AuthorizationHandlerContext ,AuthorizationHandler 需要使用
// 此上下文文对象同时也有授权结果的相关内容
IAuthorizationHandlerContextFactory contextFactory,
//对授权结果进行判断封装为 AuthorizationResult
IAuthorizationEvaluator evaluator,
//用户配置的 policy 包含在这个选项对象里
IOptions<AuthorizationOptions> options)
{
if (options == null)
throw new ArgumentNullException(nameof (options));
if (policyProvider == null)
throw new ArgumentNullException(nameof (policyProvider));
if (handlers == null)
throw new ArgumentNullException(nameof (handlers));
if (logger == null)
throw new ArgumentNullException(nameof (logger));
if (contextFactory == null)
throw new ArgumentNullException(nameof (contextFactory));
if (evaluator == null)
throw new ArgumentNullException(nameof (evaluator));
this._options = options.Value;
this._handlers = handlers;
this._policyProvider = policyProvider;
this._logger = (ILogger) logger;
this._evaluator = evaluator;
this._contextFactory = contextFactory;
}
//授权多个 IAuthorizationRequirement
public virtual async Task<AuthorizationResult> AuthorizeAsync(
ClaimsPrincipal user,
object? resource,
IEnumerable<IAuthorizationRequirement> requirements)
{
if (requirements == null)
throw new ArgumentNullException(nameof (requirements));
//在多个 policy 处理器里传递此上下文
AuthorizationHandlerContext authContext = this._contextFactory.
CreateContext(requirements, user, resource);
//异步流 这里每没有 IAuthorizationRequirement 去单体提取对应的 handler,
//asp.net 如何做到的呢
// handlers 内部会进行过滤,只处理自己能处理的 permission
foreach (IAuthorizationHandler authorizationHandler in await this._handlers.
GetHandlersAsync(authContext).ConfigureAwait(false))
{
// 用户定义的 policy handler 验证授权
await authorizationHandler.HandleAsync(authContext).ConfigureAwait(false);
if (!this._options.InvokeHandlersAfterFailure)
{
// 授权的结果在 authContext 里保存
if (authContext.HasFailed)
//只要有一个授权没有成功,余下授权验证就不执行了
break;
}
}
//authContext 把授权结果放入 authContext 对象 ,成功,失败,待定
var result = _evaluator.Evaluate(authContext);
if (result.Succeeded)
{
_logger.UserAuthorizationSucceeded();
}
else
{
_logger.UserAuthorizationFailed(result.Failure!);
}
return result;
}
public virtual async Task<AuthorizationResult> AuthorizeAsync(
ClaimsPrincipal user,object? resource,string policyName)
{
if (policyName == null)
{
throw new ArgumentNullException(nameof(policyName));
}
var policy = await _policyProvider.GetPolicyAsync(policyName).ConfigureAwait(false);
if (policy == null)
{
throw new InvalidOperationException($"No policy found: {policyName}.");
}
return await this.AuthorizeAsync(user, resource, policy).ConfigureAwait(false);
}
}
}
abp 继承 DefaultAuthorizationService 实现了 IAuthorizationService, 替换了 DefaultAuthorizationService
[Dependency(ReplaceServices = true)]
public class AbpAuthorizationService : DefaultAuthorizationService,
IAbpAuthorizationService, ITransientDependency
{
public IServiceProvider ServiceProvider { get; }
public ClaimsPrincipal CurrentPrincipal => _currentPrincipalAccessor.Principal;
private readonly ICurrentPrincipalAccessor _currentPrincipalAccessor;
public AbpAuthorizationService(
IAuthorizationPolicyProvider policyProvider,
IAuthorizationHandlerProvider handlers,
ILogger<DefaultAuthorizationService> logger,
IAuthorizationHandlerContextFactory contextFactory,
IAuthorizationEvaluator evaluator,
IOptions<AuthorizationOptions> options,
ICurrentPrincipalAccessor currentPrincipalAccessor,
IServiceProvider serviceProvider)
: base(
policyProvider,
handlers,
logger,
contextFactory,
evaluator,
options)
{
_currentPrincipalAccessor = currentPrincipalAccessor;
ServiceProvider = serviceProvider;
}
}
IPolicyEvaluator
namespace Microsoft.AspNetCore.Authorization.Policy
{
public interface IPolicyEvaluator
{
Task<AuthenticateResult> AuthenticateAsync(AuthorizationPolicy policy,
HttpContext context);
Task<PolicyAuthorizationResult> AuthorizeAsync(
AuthorizationPolicy policy,
AuthenticateResult authenticationResult,
HttpContext context,
object resource);
}
}
// 使用 IAuthorizationService 指向授权
public class PolicyEvaluator : IPolicyEvaluator
{
private readonly IAuthorizationService _authorization;
public PolicyEvaluator(IAuthorizationService authorization) =>
this._authorization = authorization;
public virtual async Task<AuthenticateResult> AuthenticateAsync(
AuthorizationPolicy policy,
HttpContext context)
{
if (policy.AuthenticationSchemes == null || policy.AuthenticationSchemes.Count <= 0)
return ((int) context.User?.Identity?.IsAuthenticated ?? 0) != 0 ?
AuthenticateResult.Success(
new AuthenticationTicket(context.User, "context.User")) : AuthenticateResult.NoResult();
ClaimsPrincipal newPrincipal = (ClaimsPrincipal) null;
//用多个 schema 去认证,获取所有的 ClaimsPrincipal
foreach (string authenticationScheme in (
IEnumerable<string>) policy.AuthenticationSchemes)
{
AuthenticateResult authenticateResult =
await context.AuthenticateAsync(authenticationScheme);
if (authenticateResult != null && authenticateResult.Succeeded)
newPrincipal = SecurityHelper.MergeUserPrincipal(
newPrincipal, authenticateResult.Principal);
}
if (newPrincipal != null)
{
context.User = newPrincipal;
return AuthenticateResult.Success(
new AuthenticationTicket(newPrincipal,
string.Join(";", (IEnumerable<string>) policy.AuthenticationSchemes)));
}
context.User = new ClaimsPrincipal((IIdentity) new ClaimsIdentity());
return AuthenticateResult.NoResult();
}
//
public virtual async Task<PolicyAuthorizationResult> AuthorizeAsync(
AuthorizationPolicy policy,
AuthenticateResult authenticationResult,
HttpContext context,
object resource)
{
if (policy == null)
throw new ArgumentNullException(nameof (policy));
return !(await AuthorizationServiceExtensions.
AuthorizeAsync(this._authorization, context.User, resource, policy)).Succeeded ?
//授权失败,但是认证成功是 Forbid,都失败 Challenge
(authenticationResult.Succeeded ? PolicyAuthorizationResult.Forbid()
: PolicyAuthorizationResult.Challenge()) : PolicyAuthorizationResult.Success();
}
}
UseAuthorization 中间件, 授权最终是如何起作用的关键
public static IApplicationBuilder UseAuthorization(this IApplicationBuilder app)
{
if (app == null)
{
throw new ArgumentNullException(nameof(app));
}
VerifyServicesRegistered(app);
app.Properties[AuthorizationMiddlewareSetKey] = true;
return app.UseMiddleware<AuthorizationMiddleware>();
}
public class AuthorizationMiddleware
{
// AppContext switch used to control whether
// HttpContext or endpoint is passed as a resource to AuthZ
private const string SuppressUseHttpContextAsAuthorizationResource
= "Microsoft.AspNetCore.Authorization.SuppressUseHttpContextAsAuthorizationResource";
// Property key is used by Endpoint routing to determine if Authorization has run
private const string AuthorizationMiddlewareInvokedWithEndpointKey =
"__AuthorizationMiddlewareWithEndpointInvoked";
private static readonly object AuthorizationMiddlewareWithEndpointInvokedValue =
new object();
private readonly RequestDelegate _next;
private readonly IAuthorizationPolicyProvider _policyProvider;
private readonly bool _canCache;
private readonly AuthorizationPolicyCache? _policyCache;
// IAuthorizationPolicyProvider 注入实现,在 abp 里会注入 AbpAuthorizationPolicyProvider
public AuthorizationMiddleware(RequestDelegate next,
IAuthorizationPolicyProvider policyProvider)
{
_next = next ?? throw new ArgumentNullException(nameof(next));
_policyProvider = policyProvider ??
throw new ArgumentNullException(nameof(policyProvider));
_canCache = false;
}
public AuthorizationMiddleware(RequestDelegate next,
IAuthorizationPolicyProvider policyProvider, IServiceProvider services) :
this(next, policyProvider)
{
ArgumentNullException.ThrowIfNull(services);
if (_policyProvider.AllowsCachingPolicies)
{
_policyCache = services.GetService<AuthorizationPolicyCache>();
_canCache = _policyCache != null;
}
}
public async Task Invoke(HttpContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
// app.UseRouting(); 这个中间件会进行发现 end point
var endpoint = context.GetEndpoint();
if (endpoint != null)
{
context.Items[AuthorizationMiddlewareInvokedWithEndpointKey] =
AuthorizationMiddlewareWithEndpointInvokedValue;
}
// Use the computed policy for this endpoint if we can
AuthorizationPolicy? policy = null;
var canCachePolicy = _canCache && endpoint != null;
//在缓存里找,会缓存 policy name 和 AuthorizationPolicy 在并发字典
if (canCachePolicy)
{
policy = _policyCache!.Lookup(endpoint!);
}
//缓存里没有
if (policy == null)
{
// IMPORTANT: Changes to authorization logic should be mirrored in MVC's AuthorizeFilter
// 获取授权 attribute 上的数据
var authorizeData = endpoint?.Metadata.GetOrderedMetadata<IAuthorizeData>()
?? Array.Empty<IAuthorizeData>();
//按照代码的意思,自定义一个 attribute 继承 AuthorizationPolicy ,也可以用来授权
var policies = endpoint?.Metadata.GetOrderedMetadata<AuthorizationPolicy>()
?? Array.Empty<AuthorizationPolicy>();
//合并所有的 AuthorizationPolicy
//通过 _policyProvider 在 authorizeData 里找到 policy
policy = await AuthorizationPolicy.CombineAsync(
_policyProvider, authorizeData, policies);
// Cache the computed policy
if (policy != null && canCachePolicy)
{
_policyCache!.Store(endpoint!, policy);
}
}
if (policy == null)
{
await _next(context);
return;
}
// IPolicyEvaluator 用的是授权服务 IAuthorizationService
// Policy evaluator has transient lifetime so it's fetched from request services instead of injecting in constructor
var policyEvaluator = context.RequestServices.
GetRequiredService<IPolicyEvaluator>();
// policy 里的 schema 去认证
var authenticateResult = await policyEvaluator.
AuthenticateAsync(policy, context);
if (authenticateResult?.Succeeded ?? false)
{
if (context.Features.Get<IAuthenticateResultFeature>()
is IAuthenticateResultFeature authenticateResultFeature)
{
authenticateResultFeature.AuthenticateResult = authenticateResult;
}
else
{
var authFeatures = new AuthenticationFeatures(authenticateResult);
context.Features.Set<IHttpAuthenticationFeature>(authFeatures);
context.Features.Set<IAuthenticateResultFeature>(authFeatures);
}
}
// Allow Anonymous still wants to run authorization to
//populate the User but skips any failure/challenge handling
// 此端点允许匿名访问直接退出
if (endpoint?.Metadata.GetMetadata<IAllowAnonymous>() != null)
{
await _next(context);
return;
}
object? resource;
if (AppContext.TryGetSwitch(SuppressUseHttpContextAsAuthorizationResource,
out var useEndpointAsResource) && useEndpointAsResource)
{
resource = endpoint;
}
else
{
resource = context;
}
//执行认证
var authorizeResult = await policyEvaluator.AuthorizeAsync(policy,
authenticateResult!, context, resource);
//
var authorizationMiddlewareResultHandler = context.RequestServices.
GetRequiredService<IAuthorizationMiddlewareResultHandler>();
//IAuthorizationMiddlewareResultHandler 处理认证结果成功继续执行,
//不成功 通过 HttpContext Challenge 或 Forbid 给客户端
await authorizationMiddlewareResultHandler.HandleAsync(
_next, context, policy, authorizeResult);
}
}
abp authorization 里使用 aop
abp 在授权方面除了扩展 asp.net core 之外,还额外可以通过 aop 对其他注入的服务继续进行授权
AuthorizationInterceptor
namespace Volo.Abp.Authorization;
public class AuthorizationInterceptor : AbpInterceptor, ITransientDependency
{
private readonly IMethodInvocationAuthorizationService
_methodInvocationAuthorizationService;
public AuthorizationInterceptor(IMethodInvocationAuthorizationService
methodInvocationAuthorizationService)
{
_methodInvocationAuthorizationService = methodInvocationAuthorizationService;
}
//拦截执行方法里先执行授权
public override async Task InterceptAsync(IAbpMethodInvocation invocation)
{
await AuthorizeAsync(invocation);
await invocation.ProceedAsync();
}
protected virtual async Task AuthorizeAsync(IAbpMethodInvocation invocation)
{
await _methodInvocationAuthorizationService.CheckAsync(
new MethodInvocationAuthorizationContext(
invocation.Method
)
);
}
}
判断哪些注入的服务能够被拦截
namespace Volo.Abp.Authorization;
public static class AuthorizationInterceptorRegistrar
{
public static void RegisterIfNeeded(IOnServiceRegistredContext context)
{
if (ShouldIntercept(context.ImplementationType))
{
context.Interceptors.TryAdd<AuthorizationInterceptor>();
}
}
private static bool ShouldIntercept(Type type)
{
return !DynamicProxyIgnoreTypes.Contains(type) &&
(type.IsDefined(typeof(AuthorizeAttribute), true) ||
AnyMethodHasAuthorizeAttribute(type));
}
private static bool AnyMethodHasAuthorizeAttribute(Type implementationType)
{
return implementationType
.GetMethods(BindingFlags.Instance | BindingFlags.Public |
BindingFlags.NonPublic)
.Any(HasAuthorizeAttribute);
}
private static bool HasAuthorizeAttribute(MemberInfo methodInfo)
{
return methodInfo.IsDefined(typeof(AuthorizeAttribute), true);
}
}
namespace Volo.Abp.Authorization
{
public interface IMethodInvocationAuthorizationService
{
Task CheckAsync(MethodInvocationAuthorizationContext context);
}
}
//通过调用 IAbpAuthorizationService 进行授权
public class MethodInvocationAuthorizationService :
IMethodInvocationAuthorizationService, ITransientDependency
{
private readonly IAbpAuthorizationPolicyProvider _abpAuthorizationPolicyProvider;
private readonly IAbpAuthorizationService _abpAuthorizationService;
public MethodInvocationAuthorizationService(
IAbpAuthorizationPolicyProvider abpAuthorizationPolicyProvider,
IAbpAuthorizationService abpAuthorizationService)
{
_abpAuthorizationPolicyProvider = abpAuthorizationPolicyProvider;
_abpAuthorizationService = abpAuthorizationService;
}
public async Task CheckAsync(MethodInvocationAuthorizationContext context)
{
if (AllowAnonymous(context))
{
return;
}
var authorizationPolicy = await AuthorizationPolicy.CombineAsync(
_abpAuthorizationPolicyProvider,
GetAuthorizationDataAttributes(context.Method)
);
if (authorizationPolicy == null)
{
return;
}
await _abpAuthorizationService.CheckAsync(authorizationPolicy);
}
protected virtual bool AllowAnonymous(MethodInvocationAuthorizationContext context)
{
return context.Method.GetCustomAttributes(true).OfType<IAllowAnonymous>().Any();
}
//获取加载方法及方法定义类型上的 IAuthorizeData 数据
protected virtual IEnumerable<IAuthorizeData>
GetAuthorizationDataAttributes(MethodInfo methodInfo)
{
var attributes = methodInfo
.GetCustomAttributes(true)
.OfType<IAuthorizeData>();
if (methodInfo.IsPublic && methodInfo.DeclaringType != null)
{
attributes = attributes
.Union(
methodInfo.DeclaringType
.GetCustomAttributes(true)
.OfType<IAuthorizeData>()
);
}
return attributes;
}
}
application-configuration
获取和用户相关的所有配置
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations;
[Area("abp")]
[RemoteService(Name = "abp")]
[Route("api/abp/application-configuration")]
public class AbpApplicationConfigurationController : AbpControllerBase,
IAbpApplicationConfigurationAppService
{
protected readonly IAbpApplicationConfigurationAppService
ApplicationConfigurationAppService;
protected readonly IAbpAntiForgeryManager AntiForgeryManager;
public AbpApplicationConfigurationController(
IAbpApplicationConfigurationAppService applicationConfigurationAppService,
IAbpAntiForgeryManager antiForgeryManager)
{
ApplicationConfigurationAppService = applicationConfigurationAppService;
AntiForgeryManager = antiForgeryManager;
}
[HttpGet]
public virtual async Task<ApplicationConfigurationDto> GetAsync(
ApplicationConfigurationRequestOptions options)
{
AntiForgeryManager.SetCookie();
return await ApplicationConfigurationAppService.GetAsync(options);
}
}