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

身份认证传递

  对于Abp比较熟悉的朋友应该对他里面的用户身份认证比较熟悉,他是通过实现微软提供的权限认证方式实现的,用户登录身份信息存储在System.Security.Claims.ClaimsPrincipal里面,但是用户的身份信息如何在不同的服务之间传递呢,不可能每一个服务都必须实现这套身份认证吧?比如我们请求调用过程如下:

  Portal站点获取用户信息没有问题,但如何传递到调用的其他微服务呢?

  这在之前文章中提到的传输Header就起到了作用,有两种方式可以处理,第一种我们可以直接把accessToken信息放到header里面,传输到服务提供者处理,服务提供程序解析里面的accessToken,赋值给Microsoft.AspNetCore.Authentication.JwtBearer. MessageReceivedContext的Token属性,参照abp里面signalr部分的身份认证信息处理,但是这里有个问题,就是没一个服务宿主应用都需要实现微软的身份认证这套逻辑;另外一种方式,我们的用户信息既然已经解析出来了,那可以直接拿到值,直接通过传输Header,传递给服务提供者,服务提供者拿到Header之后,直接给Claims赋值,这样传输的内容会少一些,并且服务不需要实现微软身份认证这套逻辑,我这里直接采用的第二种方式实现,代码如下:

  客户端Invoke方法

var abpSession = Dependency.IocManager.Instance.Resolve<IAbpSession>();
            if (!string.IsNullOrEmpty(abpSession.AccessToken)) // 将用户Token转递到其他微服务
            {
                contextNameValueCollection.Add("AccessToken", "1");
                contextNameValueCollection.Add("UserId", abpSession.UserId?.ToString());
                contextNameValueCollection.Add("UserName", abpSession.UserName);
                contextNameValueCollection.Add("TenantId", abpSession.TenantId?.ToString());
                contextNameValueCollection.Add("RoleIds", abpSession.RoleIds);

            }
            var jsonRespStr = LocalRpcRun(jsonReqStr, contextNameValueCollection);

  服务端JsonRpcProcessor类方法

public static Task<string> Process(string sessionId, string jsonRpc, object context = null)
        {
            return Task<string>.Factory.StartNew((_) =>
            {
                if ((context is Newtonsoft.Json.Linq.JObject) && (context as Newtonsoft.Json.Linq.JObject)["AccessToken"] != null) // 设置Token
                {
                    var identity = new ClaimsIdentity();
                    var accessToken = ((Newtonsoft.Json.Linq.JValue)(context as Newtonsoft.Json.Linq.JObject)["AccessToken"]).Value;
                    var userId = ((Newtonsoft.Json.Linq.JValue)(context as Newtonsoft.Json.Linq.JObject)["UserId"])?.Value;
                    var tenantId = ((Newtonsoft.Json.Linq.JValue)(context as Newtonsoft.Json.Linq.JObject)["TenantId"])?.Value;
                    var roleIds = ((Newtonsoft.Json.Linq.JValue)(context as Newtonsoft.Json.Linq.JObject)["RoleIds"])?.Value;
                    var userName = ((Newtonsoft.Json.Linq.JValue)(context as Newtonsoft.Json.Linq.JObject)["UserName"])?.Value;

                    if(userId != null) identity.AddClaim(new Claim(AbpClaimTypes.UserId, userId?.ToString()));
                    if (tenantId != null) identity.AddClaim(new Claim(AbpClaimTypes.TenantId, tenantId?.ToString()));
                    if (roleIds != null) identity.AddClaim(new Claim(AbpClaimTypes.RoleIds, roleIds?.ToString()));
                    if (userName != null) identity.AddClaim(new Claim(AbpClaimTypes.UserName, userName?.ToString()));
                    if (accessToken != null) identity.AddClaim(new Claim(AbpClaimTypes.AccessToken, accessToken.ToString()));
                    Thread.CurrentPrincipal = new ClaimsPrincipal(identity);
                }
                if (context is NameValueCollection)
                {
                    var namevalues = context as NameValueCollection;
                    if(Thread.CurrentPrincipal == null && !string.IsNullOrEmpty(namevalues.Get("AccessToken")))
                    {
                        var identity = new ClaimsIdentity();
                        var accessToken = namevalues.Get("AccessToken");
                        var userId = namevalues.Get("UserId");
                        var tenantId = namevalues.Get("TenantId");
                        var roleIds = namevalues.Get("RoleIds");
                        var userName = namevalues.Get("UserName");

                        if (userId != null) identity.AddClaim(new Claim(AbpClaimTypes.UserId, userId?.ToString()));
                        if (tenantId != null) identity.AddClaim(new Claim(AbpClaimTypes.TenantId, tenantId?.ToString()));
                        if (roleIds != null) identity.AddClaim(new Claim(AbpClaimTypes.RoleIds, roleIds?.ToString()));
                        if (userName != null) identity.AddClaim(new Claim(AbpClaimTypes.UserName, userName?.ToString()));
                        if (accessToken != null) identity.AddClaim(new Claim(AbpClaimTypes.AccessToken, accessToken.ToString()));
                        Thread.CurrentPrincipal = new ClaimsPrincipal(identity);
                    }
                }

                var tuple = (Tuple<string, string, object>)_;
                return ProcessInternal(tuple.Item1, tuple.Item2, tuple.Item3);
            }, new Tuple<string, string, object>(sessionId, jsonRpc, context));
        }

请求处理拦截

  Abp里面的拦截起点部分在ActionFilter里面,但是微服务调用没有经过ActionFilter的拦截,所以这部分需要添加到微服务处理过程中,同样是对直接调用方法的拦截,直接把代码迁移过来就可以了。

  代码片段如下:

try
            {
                // 验证权限
                var authorizationHelper = Dependency.IocManager.Instance.Resolve<IAuthorizationHelper>();
                authorizationHelper.AuthorizeAsync(mothod.First(), mothod.First().DeclaringType).Wait();
            }
            catch(AbpAuthorizationException ex)
            {
                JsonResponse response = new JsonResponse()
                {
                    Result = null,
                    Error = new JsonRpcException(-32600, "Authorize error", "The user has not permiss to " + Rpc.Method + ".", Rpc),
                    Id = Rpc.Id
                };
                callback.Invoke(response);
                CompletedProcess(Rpc, response, RpcContext);
                return response;
            }

var _unitOfWorkDefaultOptions = Dependency.IocManager.Instance.Resolve<IUnitOfWorkDefaultOptions>();
                var _unitOfWorkManager = Dependency.IocManager.Instance.Resolve<IUnitOfWorkManager>();
                var unitOfWorkAttr = _unitOfWorkDefaultOptions.GetUnitOfWorkAttributeOrNull(mothod.First());

                object results;

                if (!unitOfWorkAttr.IsDisabled)
                {
                    using (var uow = _unitOfWorkManager.Begin(unitOfWorkAttr.CreateOptions()))
                    {
                        results = newDel.DynamicInvoke(parameters);
                        uow.Complete();
                    }
                }
                else
                {
                    results = newDel.DynamicInvoke(parameters);
                }

原文地址:https://www.cnblogs.com/spritekuang/p/10805737.html

时间: 2024-08-28 21:25:28

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

企业级工作流解决方案(三)--微服务消息处理模型之服务端处理

1. Json-Rpc 2.0 参考地址:https://www.jsonrpc.org/specification JSON-RPC是一个无状态且轻量级的远程过程调用(RPC)协议,它允许运行在基于socket,http等诸多不同消息传输环境的同一进程中.其使用JSON(RFC 4627)作为数据格式,它为简单而生. 请求对象 发送一个请求对象至服务端代表一个rpc调用, 一个请求对象包含下列成员: jsonrpc指定JSON-RPC协议版本的字符串,必须准确写为“2.0” method包含所

企业级工作流解决方案(四)--微服务消息处理模型之消息传输通道

消息传输通道我这里只定义了3种,即:localInvoker,HttpInvoker,TcpInvoker,根据实际的情况,还可以进行扩展,比如消息队列,不过这都是后话了,先重点描述一下这3种方式. LocalInvoker 本地调用直接构造请求参数,直接调用服务端的JsonRpcProcessor服务处理执行服务处理过程,这个不多说. HttpInvoker 即执行http请求处理过程,由于.net framework和.net core的运行机制有所不同,处理方式也有所不同,但最终都落到服务

企业级工作流解决方案(五)--微服务消息处理模型之客户端端处理

微服务的服务端已经启动起来了,服务消费者怎么知道服务在哪个地方,通过什么方式调用呢,分布式如何选择正确的服务器调用服务? 这个就涉及到服务发现.服务健康检查的问题了,很多微服务架构的做法都是通过消息队列来实现的,消息队列天生就支持发布订阅功能,服务有变化之后,发布通知,每个消费者更新状态,还涉及到更新服务的metadata信息,同时还涉及到服务健康检查等等一系列功能,其实这些地方是非常容易出问题的地方,但是对于规模流量不是特别巨大的企业,这部分职责可以进行转移,服务的发现就直接通过配置文件实现,

企业级工作流解决方案(一)--总体介绍

引言:国内对于流程引擎的介绍非常的少,但是不能否认流程引擎的重要性,流程引擎在各个行业都有应用,OA管理的请假流程.出差流程,项目管理上的合同审批流程.验收流程.启动流程,Erp中的采购流程.入库出库流程,政府里面的招标流程.结算流程等,都有流程引擎的身影,当然这里说的流程指审批意义的流程,还有一些不用人为参与的生产作业生产过程也是可以用工作流来解决的. 工作了多年,是时候把工作中的一些东西沉淀下来,准备写一系列文章,系统的介绍企业级工作流管理平台的搭建以及设计思路,希望能对其他人有所帮助.这一

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

服务端启动 服务端启动主要做几件事情,1. 从配置文件读取服务配置(主要是服务监听端口和编解码配置),2. 注册编解码器工厂,3. 启动dotnetty监听端口,4. 读取配置文件,解析全局消息处理模型5. 注册服务端处理对象到容器. JsonRpcServerModule代码如下,见备注说明 [DependsOn(typeof(AbpKernelModule))] public class JsonRpcServerModule : AbpModule { public override vo

企业级工作流解决方案(二)--微服务总体介绍

微服务好处和概念性的东西就不介绍了,对于微服务,个人认为并不是越复杂就越好,相反要结合自己公司的现状,适当的做一些裁剪,比如对于规模和业务量不是特别大的企业,就没有必要把服务总线,服务健康检查,服务路由选择,熔断等等加进来,相反,这一部分职责可以通过配置文件,nginx代理,api网关等等外围的技术来控制,当企业达到一定的规模之后,再来完善这部分内容,但是对于微服务处理过程来说,没有任何影响. 我这里根据json-rpc 2.0标准,结合网上一些开源的微服务架构思想,采用dotnetty技术,搭

微服务操作模型

这里并不是介绍微服务概念,如需要了解微服务,可以阅读Fowler-Microservices文章.本博客假定我们已开始使用微服务解耦单体应用,用来提升可部署性和可扩展性. 当我们在系统范围内部署大量的微服务时,一个新的挑战产生了,单体应用部署时不会发生.这篇文章将针对这些新的挑战,在系统范围内部署大量微服务时定义一套操作模型(operations model). 这篇文章分为如下几个部分: 前提条件: 扩展: 问题: 需要的组件: 参考模型: 下一步: 1. 前提条件 当在系统范围内需要部署大量

spring cloud微服务分布式云架构 - Spring Cloud集成项目简介

Spring Cloud集成项目有很多,下面我们列举一下和Spring Cloud相关的优秀项目,我们的企业架构中用到了很多的优秀项目,说白了,也是站在巨人的肩膀上去整合的.在学习Spring Cloud之前大家必须了解一下相关项目,希望可以帮助到大家. Spring Cloud Config 配置管理工具包,让你可以把配置放到远程服务器,集中化管理集群配置,目前支持本地存储.Git以及Subversion. Spring Cloud Bus ?事件.消息总线,用于在集群(例如,配置变化事件)中

(三)spring cloud微服务分布式云架构 - Spring Cloud集成项目简介

Spring Cloud集成项目有很多,下面我们列举一下和Spring Cloud相关的优秀项目,我们的企业架构中用到了很多的优秀项目,说白了,也是站在巨人的肩膀上去整合的.在学习Spring Cloud之前大家必须了解一下相关项目,希望可以帮助到大家. Spring Cloud Config 配置管理工具包,让你可以把配置放到远程服务器,集中化管理集群配置,目前支持本地存储.Git以及Subversion. Spring Cloud Bus ?事件.消息总线,用于在集群(例如,配置变化事件)中