权限系统主要定义为管理员增删改查权限数据,直接读取数据库,权限系统服务主要定义为供其他系统调用的权限验证接口,定义为两个不同的微服务。

  权限系统有一个特点,数据变动比较小,数据量本身并不是很大,访问量非常大,项目如果做了后端权限验证(其实为了项目数据的安全,必须每一个模块都需要做后端权限验证),那么每访问一个功能模块都会访问权限相关的数据。

  权限系统可能是集中管理的,即每一个不同的系统都需要访问权限中心数据,那这个访问量就会成倍的增加。

  我看到的很多权限控制都是直接读取数据库,这个带来的问题也很明显,性能较差,数据库压力大,包括Abp框架以及他的zero项目,数据库及项目性能都受权限系统拖累。

  基于以上原因,权限系统完全可以存储到缓存中。

Abp中的缓存

  Abp中是通过ICacheManager进行缓存管理了,他只是一个容器,真正的缓存是实现了ICache的类,Abp实现了两种缓存,一个是基于内存的AbpMemoryCache(Microsoft.Extensions.Caching.Memory. MemoryCache),一个是基于Redis的AbpRedisCache(使用StackExchange.Redis)

  单节点部署,直接用AbpMemoryCache即可,如果是分布式部署,则最好用Memcached实现,权限数据不需要持久化到物理介质,纯缓存。

缓存Key设计

  缓存Key格式定义为“AuthCenterService.实体名称.租户Id”,租户Id为空,固定写为-1,如果没有存储租户Id,则缓存整张表数据。代码示例:

public List<SEC_Dept> GetTenantSEC_Depts(int? tenantId)
{
string strTenant = tenantId.HasValue ? tenantId.Value.ToString() : "-1";
return _cache.Get($"{AuthCenterServiceModule.ModuleName}.{AuthCenterCacheConst.SEC_Dept}.{strTenant}", () => GetFromRepository(false,tenantId));
} public List<SEC_Dept> GetAllSEC_Depts()
{
return _cache.Get($"{AuthCenterServiceModule.ModuleName}.{AuthCenterCacheConst.SEC_Dept}.All", () => GetFromRepository(true));
} public List<SEC_Dept> GetFromRepository(bool isAll, int? tenantId = null)
{
UnitOfWorkOptions unitOfWorkOptions = new UnitOfWorkOptions();
unitOfWorkOptions.IsTransactional = false;
unitOfWorkOptions.IsReadDb = true;
using (var uow = _unitOfWorkManager.Begin(unitOfWorkOptions))
{
if (isAll)
{
_unitOfWorkManager.Current.DisableFilter(AbpDataFilters.MayHaveTenant);
var result = _repository.GetAllList();
uow.Complete();
return result;
}
else
{
_unitOfWorkManager.Current.SetTenantId(tenantId);
var result = _repository.GetAllList();
uow.Complete();
return result;
}
}
}

缓存Key的清除

  在权限数据有变换,或者有些情况人为的修改了权限数据,需要定义接口,删除对应的缓存,代码如下:

/// <summary>
/// 清空租户部门缓存
/// </summary>
/// <param name="tenantId">租户Id</param>
public void ClearSEC_DeptCache(int? tenantId)
{
string strTenant = tenantId.HasValue ? tenantId.Value.ToString() : "-1";
var cacheKey = $"{AuthCenterServiceModule.ModuleName}.{AuthCenterCacheConst.SEC_Dept}.{strTenant}";
_cache.Remove(cacheKey);
}
/// <summary>
/// 清空特定租户权限管理所有缓存
/// </summary>
public void ClearTenantAll(int? tenantId)
{
ClearSEC_AdminUserCache(tenantId);
ClearSEC_ModuleCache(tenantId);
ClearSEC_OperateCache(tenantId);
ClearSEC_RoleCache(tenantId);
ClearSEC_DeptCache(tenantId);
ClearSEC_ModuleSEC_RoleCache(tenantId);
ClearSEC_OperateSEC_RoleCache(tenantId);
ClearSEC_RoleSEC_AdminUserCache(tenantId);
}

  定义数据修改事件,页面修改了权限数据,触发事件,调用权限系统提供的服务,清除对应的缓存。

public class SEC_DeptEventHandler : IEventHandler<EntityChangedEventData<SEC_Dept>>, ISingletonDependency
{
private readonly IAbpSession _abpSession;
public SEC_DeptEventHandler(IAbpSession abpSession)
{
_abpSession = abpSession;
}
public void HandleEvent(EntityChangedEventData<SEC_Dept> eventData)
{
Rpc.Call<dynamic>("AuthCenterService.AuthCenterCacheAppService.ClearSEC_DeptCache", _abpSession.TenantId);
}
}

操作权限验证

  操作权限验证可能在用户的每一个动作都会触发,我这里的设计是用户在登录的时候,把用户的所有角色Id解析出来,存储到accesstoken信息里面(自定义Claims),修改Abp里面的IAbpSession接口,增加RoleIds字段(和UserId一样,从Claims里面读取),将每一个操作Code对应的角色Id集合存储到缓存里面,那么验证用户是否拥有某一个操作权限时,直接从缓存里面读取角色Id集合,判断用户拥有的角色Id是否包含在里面,达到验证目的。

public interface IAbpSession
{
// ...... /// <summary>
/// 存储用户角色Id集合,用于操作权限验证
/// </summary>
string RoleIds { get; } /// <summary>
/// 用户请求的Token
/// </summary>
string AccessToken { get; }
}

  在构造AccessToken的时候,添加RoleIds申明

public AuthenticateResultModel Authenticate(LoginResultModel loginResultModel)
{
List<Claim> claims = new List<Claim>();
claims.Add(new Claim(AbpClaimTypes.UserId, loginResultModel.UserId.ToString()));
if (loginResultModel.TenantId.HasValue)
{
claims.Add(new Claim(AbpClaimTypes.TenantId, loginResultModel.TenantId.ToString()));
}
claims.Add(new Claim(AbpClaimTypes.RoleIds, loginResultModel.RoleIds)); // 添加用户角色申明
claims.Add(new Claim(AbpClaimTypes.UserName, loginResultModel.UserName)); var accessToken = CreateAccessToken(claims); return new AuthenticateResultModel
{
AccessToken = accessToken,
EncryptedAccessToken = GetEncrpyedAccessToken(accessToken),
ExpireInSeconds = (int)_configuration.Expiration.TotalSeconds,
UserId = loginResultModel.UserId
};
}

  操作权限验证

public bool CheckAdminUserOperate(string roleIds, int? tenantId, string operateCode)
{
if (string.IsNullOrEmpty(roleIds))
{
return false;
}
var strOperateRoleIds = GetOperateRoleIdsFromCache(tenantId, operateCode);
if (string.IsNullOrEmpty(strOperateRoleIds))
{
return false;
}
strOperateRoleIds = ";" + strOperateRoleIds + ";";
var userRoleIds = roleIds.Split(new char[] { ';' });
return userRoleIds.Any(r => strOperateRoleIds.Contains($";{r};"));
} private string GetOperateRoleIdsFromCache(int? tenantId, string operateCode)
{
string strTenant = tenantId.HasValue ? tenantId.Value.ToString() : "-1";
var cacheOperateRoleIdss = _cache.Get($"{AuthCenterServiceModule.ModuleName}.{AuthCenterCacheConst.OperateRoleIds}.{strTenant}"
                        , () => GetOperateRoleIds());
if (!cacheOperateRoleIdss.ContainsKey(operateCode))
{
cacheOperateRoleIdss.Add(operateCode, GetOperateRoleIds(tenantId, operateCode));
}
return cacheOperateRoleIdss[operateCode];
} private string GetOperateRoleIds(int? tenantId, string operateCode)
{
var tennantOperate = _sEC_OperateDomainService.GetTenantSEC_Operates(tenantId).FirstOrDefault(r => r.Code == operateCode);
if (tennantOperate == null)
{
return string.Empty;
}
return _sEC_OperateSEC_RoleDomainService.GetTenantSEC_OperateSEC_Roles(tenantId).Where(r => r.SEC_Operate_Id == tennantOperate.Id)
            .Select(r => r.SEC_Role_Id.ToString()).Aggregate((r, t) => r + ";" + t); }

企业级工作流解决方案(十一)--集成Abp和ng-alain--权限系统服务的更多相关文章

  1. 企业级工作流解决方案(十二)--集成Abp和ng-alain--用户身份认证与权限验证

    多租户 如果系统需要支持多租户,那么最好事先定义好多租户的存储部署方式,Abp提供了几种方式,根据需要选择,每一个用户身份认证与权限验证都需要完全的隔离 这里设计的权限数据全部存储在缓存中,每个租户单 ...

  2. 企业级工作流解决方案(十三)--集成Abp和ng-alain--数据库读写分离

    说到程序里面数据库管理,无非就是两件事情,一是数据库操作,对于数据库的操作,各种程序语言都有封装,也就是所谓的ORM框架,.net 方向一般用得比较多和就是.net framework和dapper, ...

  3. 企业级工作流解决方案(十五)--集成Abp和ng-alain--Abp其他改造

    配置功能增强 Abp定义了各种配置接口,但是没有定义这些配置数据从哪里来,但是管理配置数据对于一个应用程序来说,是必不可少的一件事情. .net的配置数据管理,一般放在Web.config文件或者Ap ...

  4. 企业级工作流解决方案(十四)--集成Abp和ng-alain--自动化脚本

    对于.net方向,做过自动化的,应该没有人不熟悉msbuild吧,非常强大的代码编译工具,.net平台的编译工作都是交给他来完成的,包括.net core的命令,本质上都是调用msbuild来执行的 ...

  5. 企业级工作流解决方案(十)--集成Abp和ng-alain--权限系统

    权限系统 应用系统离不开权限控制,权限中心不一定能抽象出所有的业务场景,这里定义的权限系统不一定能够满足所有的场景,但应该可以满足多数的业务需求. Abp的zero项目也定义了权限相关的表,但里面很多 ...

  6. 企业级工作流解决方案(六)--微服务消息处理模型之与Abp集成

    身份认证传递 对于Abp比较熟悉的朋友应该对他里面的用户身份认证比较熟悉,他是通过实现微软提供的权限认证方式实现的,用户登录身份信息存储在System.Security.Claims.ClaimsPr ...

  7. 企业级工作流解决方案(八)--微服务Tcp消息传输模型之服务端处理

    服务端启动 服务端启动主要做几件事情,1. 从配置文件读取服务配置(主要是服务监听端口和编解码配置),2. 注册编解码器工厂,3. 启动dotnetty监听端口,4. 读取配置文件,解析全局消息处理模 ...

  8. 企业级工作流解决方案(九)--微服务Tcp消息传输模型之客户端处理

    客户端启动 客户端启动主要做三件事情,1. 从配置文件读取服务调用配置,存储到全局对象中.2. 指定客户端编解码器工厂.3. 预连接,即预先建立与服务端的通信Chanel. [DependsOn(ty ...

  9. 企业级工作流解决方案(七)--微服务Tcp消息传输模型之消息编解码

    Tcp消息传输主要参照surging来做的,做了部分裁剪和改动,详细参见:https://github.com/dotnetcore/surging Json-rpc没有定义消息如何传输,因此,Jso ...

随机推荐

  1. 【Azure媒体服务 Azure Media Service】Azure Media Service中Stream Endpoint 说明 (流式处理终结点)

    Azure 媒体服务是一个基于云的媒体工作流平台,用于生成需要编码.打包.内容保护和直播活动广播的解决方案. 在视频的直播,点播方案中,媒体服务的架构主要由三部分构成: 推流端,把本地视频或直播内容推 ...

  2. javaSE、javaEE、Android知识点总结

    曾今上学时候的一些学习总结,如有错误请大家指出,共同学习. 1. 什么是WebView? WebView是一个使用WebKit引擎的浏览器组件,用来加载网页. 2. WebView中加载网页的两种方式 ...

  3. buuoj[ACTF_Junior_2020]Splendid_MineCraft WriteUp

    Splendid_MineCraft 题目标题就已经暗示这题是SMC了(self-modifying code). 工具:exeinfo,x32dbg和IDA7.0 先丢进exeinfo里查看相关信息 ...

  4. App 后台架构

    转载请注明出处:http://blog.csdn.net/smartbetter/article/details/53933096 做App做的久了,就想研究一下与之相关的App后台,发现也是蛮有趣的 ...

  5. 使用 k8s 搭建 confluence 6.10.x 版本

    将公司中已有的 confluence 服务迁移到 k8s 集群中,需要保留当前已有的数据.整体需要分为如下几个步骤: 备份 mysql 数据 备份 confluence 安装目录 备份 conflue ...

  6. 我用 Python 撸了一个 plist 图集拆图工具!附上github源码

    这些年,我一直在使用 JavaScript .CocosCreator 做开发,只要是他们不能解决的,我都不太愿意去弄,或者说是不太情愿去做.真的是手中有把锤子,看什么都是钉子,越是熟悉一样东西,越容 ...

  7. 不吹不黑,跨平台框架AspNetCore开发实践杂谈

    前言 最近边学边做,初步上手了AspNetCore的开发,对MVC这套熟悉了一下,因为之前没有拿来做过独立项目,都是和别人合作开发,所以前后端分离,我都只做WebApi,而且还是很小的项目(课设级别) ...

  8. Git的介绍及使用

    一.配置用户信息: 配置用户名和邮箱: $ git config --global user.name "chunyu" $ git config --global user.em ...

  9. 如何使用捷映App制作朋友圈九宫格视频图片合集

    在刷朋友圈的过程中,看到九宫格的视频图片合集,带有酷炫的音效和动效,展现效果非常好,那么我们该如何制作呢?下面我为大家介绍. 第一步,我们需要在各大应用市场搜索[捷映视频制作]App,点击[安装]. ...

  10. 修改redo log 的大小

    alert日志中含有大量警告信息:"Thread 1 cannot allocate new log, sequence 320xx Checkpoint not complete" ...