[Abp vNext 源码分析] - 7. 权限与验证 (7)

这里我们以 UserPermissionValueProvider 为例,来看看它的实现方法。

public class UserPermissionValueProvider : PermissionValueProvider { // 提供者的名称。 public const string ProviderName = "User"; public override string Name => ProviderName; public UserPermissionValueProvider(IPermissionStore permissionStore) : base(permissionStore) { } public override async Task<PermissionGrantResult> CheckAsync(PermissionValueCheckContext context) { // 从传入的 Principal 中查找 UserId,不存在则说明没有定义,视为未授权。 var userId = context.Principal?.FindFirst(AbpClaimTypes.UserId)?.Value; if (userId == null) { return PermissionGrantResult.Undefined; } // 调用 IPermissionStore 从持久化存储中,检测指定权限在某个提供者下面是否已经被授予了权限。 // 如果被授予了权限, 则返回 true,没有则返回 false。 return await PermissionStore.IsGrantedAsync(context.Permission.Name, Name, userId) ? PermissionGrantResult.Granted : PermissionGrantResult.Undefined; } }

这里我们先不讲 IPermissionStore 的具体实现,就上述代码来看,ABP vNext 是将权限定义放在了一个管理容器(IPermissionDeftiionManager)。然后又实现了自定义的策略处理器和策略,在处理器的内部又通过 IPermissionChecker 根据不同的 PermissionValueProvider 结合 IPermissionStore 实现了指定用户标识到权限的检测功能。

2.2.7 权限验证拦截器

权限验证拦截器的注册都是在 AuthorizationInterceptorRegistrar 的 RegisterIfNeeded() 方法内实现的,只要类型的任何一个方法标注了 AuthorizeAttribute 特性,就会被关联拦截器。

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); }

拦截器和类型关联之后,会通过 IMethodInvocationAuthorizationService 的 CheckAsync() 方法校验调用者是否拥有指定权限。

public override async Task InterceptAsync(IAbpMethodInvocation invocation) { // 防止重复检测。 if (AbpCrossCuttingConcerns.IsApplied(invocation.TargetObject, AbpCrossCuttingConcerns.Authorization)) { await invocation.ProceedAsync(); return; } // 将被调用的方法传入,验证是否允许访问。 await AuthorizeAsync(invocation); await invocation.ProceedAsync(); } protected virtual async Task AuthorizeAsync(IAbpMethodInvocation invocation) { await _methodInvocationAuthorizationService.CheckAsync( new MethodInvocationAuthorizationContext( invocation.Method ) ); }

在具体的实现当中,首先检测方法是否标注了 IAllowAnonymous 特性,标注了则说明允许匿名访问,直接返回不做任何处理。否则就会从方法获取实现了 IAuthorizeData 接口的特性,从里面拿到 Policy 值,并通过 IAuthorizationService 进行验证。

protected async Task CheckAsync(IAuthorizeData authorizationAttribute) { if (authorizationAttribute.Policy == null) { // 如果当前调用者没有进行认证,则抛出未登录的异常。 if (!_currentUser.IsAuthenticated && !_currentClient.IsAuthenticated) { throw new AbpAuthorizationException("Authorization failed! User has not logged in."); } } else { // 通过 IAuthorizationService 校验当前用户是否拥有 authorizationAttribute.Policy 权限。 await _authorizationService.CheckAsync(authorizationAttribute.Policy); } }

针对于 IAuthorizationService ,ABP vNext 还是提供了自己的实现 AbpAuthorizationService,里面没有重写什么方法,而是提供了两个新的属性,这两个属性是为了方便实现 AbpAuthorizationServiceExtensions 提供的扩展方法,这里不再赘述。

三、总结

关于权限与验证部分我就先讲到这儿,后续文章我会更加详细地为大家分析 ABP vNext 是如何进行权限管理,又是如何将 ABP vNext 和 ASP.NET Identity 、IdentityServer4 进行集成的。

ABP vNext 系列文章总目录

本篇文章的 PDF 版本

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpzzps.html