ABP Identity
ABP Identity
2023/6/1
➡️

类关系

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 提供的基础服务构建用户自己的服务

  1. RoleAppService
  2. UserAppService
  3. OrganizationUnitAppService
  4. 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

  1. ClientPermissionValueProvider : 从当前声明中拿到当前客户端并检查客户端是否具有指定的权 限. 这在没有当前登录用户的客户端交互特别有用. 客户端声明由 AbpClaimTypes.ClientId 静态 属性定义
  2. RolePermissionValueProvider : 从当前的声明中拿到授予当前用户的角色集合并且判断角色是否 具有指定的权限. 角色声明由 AbpClaimTypes.Role 静态属性定义
  3. UserPermissionValueProvider : 从当前的声明中拿到当前用户 ID 并检查用户授权. 用户声明由 AbpClaimTypes.UserId 静态属性定义
  4. 用户也可以定义自己的 PermissionValueProvider,用于自定义权限检查

PermissionValueProvider 的 CheckAsync 应该返回下面三个值之一:

  1. PermissionGrantResult.Granted 授予用户权限,如果没有其他的授权值提供程序返回 Prohibited, 那么最后会返回 Granted.
  2. PermissionGrantResult.Prohibited 禁止授权用户,任何一个授权值提供程序返回了 Prohibited, 那么其他的提供程序返回的值都不再重要.
  3. 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);
    }
}
👍🎉🎊