zoukankan      html  css  js  c++  java
  • 企业级工作流解决方案(六)--微服务消息处理模型之与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);
                    }
  • 相关阅读:
    软件项目管理
    asterisk channel driver dev ref
    标 题: 有什么办法快速把pc上的网址发送到手机上
    dongle0
    ubuntu
    Huawei E1750 Asterisk
    Jquery重新学习之七[Ajax运用总结A]
    Jquery重新学习之六[操作XML数据]
    Jquery重新学习之五[操作JSON数据]
    Jquery重新学习之四[核心属性与文档处理属性]
  • 原文地址:https://www.cnblogs.com/spritekuang/p/10805737.html
Copyright © 2011-2022 走看看