权限的定义与 Feature 一样,都是存放了一些基本信息,比如说权限的唯一标识,权限的展示名称与描述,只不过少了 Feature 的附加属性而已。下面我们就会加快进度来说明一下权限相关的知识。
2.3.2 权限检测器权限相比于功能,权限更加细化到了用户与角色,角色通过与权限关联,角色就是一个权限组的集合,用户再跟角色进行关联。看看权限管理器的定义吧:
public abstract class PermissionChecker<TRole, TUser> : IPermissionChecker, ITransientDependency, IIocManagerAccessor where TRole : AbpRole<TUser>, new() where TUser : AbpUser<TUser>还是相对而言比较简单的,在这里你只需要关注两个东西:
public virtual async Task<bool> IsGrantedAsync(string permissionName) { return AbpSession.UserId.HasValue && await _userManager.IsGrantedAsync(AbpSession.UserId.Value, permissionName); } public virtual async Task<bool> IsGrantedAsync(long userId, string permissionName) { return await _userManager.IsGrantedAsync(userId, permissionName); }这就是权限校验的实现,第一个是传入当前用户的 Id 扔到 _userManager 进行校验,而第二个则扔一个用户制定的 Id 进行校验。
看到这里,我们又该到下一节了,讲解一下这个 _userManager 是何方神圣。
2.3.3 用户管理器如果读者接触过 ASP.NET Core MVC 的 Identity 肯定对于 UserManager<,> 不会陌生,没错,这里的 _userManager 就是继承自 UserManager<TUser, long>, 实现的 AbpUserManager<TRole, TUser>。
继续我们还是看关键方法 IsGrantedAsync()。
public virtual async Task<bool> IsGrantedAsync(long userId, string permissionName) { // 传入用户 ID 与需要检测的权限,通过权限管理器获得 Permission 对象 return await IsGrantedAsync( userId, _permissionManager.GetPermission(permissionName) ); }还是个空壳子,继续跳转:
public virtual async Task<bool> IsGrantedAsync(long userId, Permission permission) { // 首先检测当前用户是否拥有租户信息 if (!permission.MultiTenancySides.HasFlag(GetCurrentMultiTenancySide())) { return false; } // 然后检测权限依赖的功能,如果功能没有启用,一样的是没权限的 if (permission.FeatureDependency != null && GetCurrentMultiTenancySide() == MultiTenancySides.Tenant) { FeatureDependencyContext.TenantId = GetCurrentTenantId(); if (!await permission.FeatureDependency.IsSatisfiedAsync(FeatureDependencyContext)) { return false; } } // 获得当前用户所拥有的权限,没有权限一样滚蛋 var cacheItem = await GetUserPermissionCacheItemAsync(userId); if (cacheItem == null) { return false; } // 检测当前用户是否被授予了特许权限,没有的话则直接跳过,有的话说明这是个特权用户,拥有这个特殊权限 if (cacheItem.GrantedPermissions.Contains(permission.Name)) { return true; } // 检测禁用权限名单中是否拥有本权限,如果有,一样的不通过 if (cacheItem.ProhibitedPermissions.Contains(permission.Name)) { return false; } // 检测用户角色是否拥有改权限 foreach (var roleId in cacheItem.RoleIds) { if (await RoleManager.IsGrantedAsync(roleId, permission)) { return true; } } return false; }这里我们没有讲解权限管理器与权限的注入是因为他们两个简直一毛一样好吧,你可以看看权限的定义:
public class MyAuthorizationProvider : AuthorizationProvider { public override void SetPermissions(IPermissionDefinitionContext context) { var administration = context.CreatePermission("Administration"); var userManagement = administration.CreateChildPermission("Administration.UserManagement"); userManagement.CreateChildPermission("Administration.UserManagement.CreateUser"); var roleManagement = administration.CreateChildPermission("Administration.RoleManagement"); } }是不是感觉跟功能的 Provider 很像...
权限仅仅会与用于和角色挂钩,与租户无关,它和功能的实现大同小异,但是也是值得我们借鉴学习的。
3.多租户数据过滤租户与租户之间是如何进行数据过滤的呢?
这里简单讲一下单部署-单数据库的做法吧,在 EF Core 当中针对每一个实体都提供了一个全局过滤的方法 HasQueryFilter,有了这个东西,在每次 EF Core 进行查询的时候都会将查询表达式附加上你自定义的过滤器一起进行查询。