/// <summary>
        /// 授权接入 SSO
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public IActionResult AuthMapping(AuthMappingRequestModel data)
        {
            #region 验证SiteToken
            if (ssoConfigs.SiteToken != data.SiteToken)
            {
                return(View(data));
            }
            #endregion

            #region 向 Server 做回调验证,谨防伪造
            var callBackRequest = new AuthMappingCallBackRequestModel()
            {
                AppKey    = ssoConfigs.AppKey,
                SsoUserId = data.SsoUserId
            };
            var postData        = JsonConvert.SerializeObject(callBackRequest);
            var resrponseStr    = httpPostHelper.Send(ssoConfigs.AuthMappingCallBack, postData);
            var reswponseObject = JsonConvert.DeserializeObject <AuthMappingCallBackResponseModel>(resrponseStr);
            if (reswponseObject == null || !reswponseObject.Success)
            {
                //TODO
                //若未登录,则跳转到登录页
                //若已登录,则跳转到授权接入页
                return(Redirect(data.TargetUrl));
            }
            #endregion

            #region 新增UserMapping记录
            int userId = loginHelper.GetUserId(HttpContext);
            if (userId > 0)
            {
                UserMapping userMapping = new UserMapping()
                {
                    UserId    = userId,
                    SsoUserId = data.SsoUserId
                };
                siteContext.UserMapping.Add(userMapping);
                siteContext.SaveChanges();

                return(RedirectToAction("RedirectToSite", new { TargetUrl = data.TargetUrl }));
            }
            else
            {
                return(View(data));
            }
            #endregion
        }
Beispiel #2
0
        /// <summary>
        /// 请求登录第三方系统
        /// </summary>
        /// <returns></returns>
        public IActionResult RedirectToSite(RedirectToSiteRequestModel data)
        {
            /*
             * 1.检查用户是否登录
             * 2.检查是否存在SSO中的UserToken
             *   若不存在,则请求 sso Authentication/AuthRedirectToSite 获取UserToken
             * 3.判断UserToken
             *   若不存在,则返回认证失败
             *   若存在,则重定向到 sso Authentication/RedirectToSite
             * */
            //1.检查用户是否登录
            if (!loginHelper.IsLogin(HttpContext))
            {
                return(Redirect(ssoConfigs.AuthFail));
            }

            var userIdClaim    = HttpContext.User.Claims.FirstOrDefault(x => x.Type == SessionConstants.UserIdScheme);
            var userTokenClaim = HttpContext.User.Claims.FirstOrDefault(x => x.Type == SessionConstants.UserTokenScheme);

            var userId    = userIdClaim == null ? "" : userIdClaim.Value;
            var userToken = userTokenClaim == null ? "" : userTokenClaim.Value;

            var mapping   = siteContext.UserMapping.FirstOrDefault(x => x.UserId == int.Parse(userId));
            var ssoUserId = mapping == null ? 0 : mapping.SsoUserId;

            //检查 userId
            if (string.IsNullOrWhiteSpace(userId))
            {
                return(Redirect(ssoConfigs.AuthFail));
            }

            //2.检查 UserToken
            if (string.IsNullOrWhiteSpace(userToken))
            {
                var siteToken    = ssoConfigs.SiteToken;
                var requestModel = new AuthRedirectToSiteRequesModel()
                {
                    UserId    = int.Parse(userId),
                    SsoUserId = ssoUserId,
                    TargetUrl = data.TargetUrl,
                    FailUrl   = ssoConfigs.AuthFail
                };

                var responseStr    = httpPostHelper.Send(ssoConfigs.AuthRedirectToSite, JsonConvert.SerializeObject(requestModel));
                var responseObject = JsonConvert.DeserializeObject <AuthRedirectToSiteResponseModel>(responseStr);
                if (responseObject == null || !responseObject.Success || string.IsNullOrWhiteSpace(responseObject.UserToken))
                {
                    return(Redirect(ssoConfigs.AuthFail));
                }
                userToken = responseObject.UserToken;
            }

            string url = $"{ssoConfigs.RedirectToSite}?AppKey={ssoConfigs.AppKey}&UserToken={userToken}&UserId={userId}&SsoUserId={ssoUserId}&TargetUrl={data.TargetUrl}&FailUrl={ssoConfigs.AuthFail}";

            return(Redirect(url));
        }
Beispiel #3
0
        /// <summary>
        /// 获取登录用户的UserToken
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public AuthRedirectToSiteResponseModel AuthRedirectToSite()
        {
            /*
             * 1.验证 AppKey、签名
             * 2.验证 UserToken
             *   a.有SsoUserId,则根据SsoUserId 加上 SourceSiteConfigId、TargerSiteConfigId 获取用户信息
             *   b.无SsoUserId,则根据 UserId、SourceSiteCofnigId 获取用户信息
             * 3.向请求 client 发送 AuthCallBack 回调验证,确认此请求是正常请求还是别人伪造的请求
             *   若为伪造的请求,则直接返回请求认证失败信息以及提示,终止请求
             * 4.若第2步中,获取不到用户信息,则创建 User 信息
             * 5.返回验证成功信息,以及UserToken
             * */
            AuthRedirectToSiteRequesModel data = null;
            var appKey  = HttpContext.Request.Headers[HttpHeaders.AppKey];
            var disgest = HttpContext.Request.Headers[HttpHeaders.Disgest];

            var reader  = new StreamReader(Request.Body);
            var bodyStr = reader.ReadToEnd();

            data = JsonConvert.DeserializeObject <AuthRedirectToSiteRequesModel>(bodyStr);

            #region 验证签名
            byte[] body = Encoding.UTF8.GetBytes(bodyStr);
            if (!computeHashHelper.IsComputeHash(disgest, body))
            {
                return(new AuthRedirectToSiteResponseModel()
                {
                    Success = false,
                    Code = 1,
                    Message = "ComputeHash wrong."
                });
            }
            #endregion


            #region 验证 AppKey
            //#TODO 后续需要将 SiteConfig 缓存起来,不要每次查询
            var siteConfig = siteContext.SiteConfig.FirstOrDefault(x => x.AppKey == appKey);
            if (siteConfig == null)
            {
                return(new AuthRedirectToSiteResponseModel()
                {
                    Success = false,
                    Code = 2,
                    Message = "AppKey wrong."
                });
            }
            #endregion

            #region 验证跳转地址
            Uri TargetUrl = new Uri(data.TargetUrl);
            var tagerHost = TargetUrl.Authority.ToUpper();
            //#TODO 后续需要将 SiteConfig 缓存起来,不要每次查询
            var tagerSiteConfig = siteContext.SiteConfig.FirstOrDefault(x => x.Host == tagerHost);
            if (tagerSiteConfig == null)
            {
                return(new AuthRedirectToSiteResponseModel()
                {
                    Success = false,
                    Code = 3,
                    Message = "TargetUrl wrong."
                });
            }
            #endregion

            #region 验证用户是否存在,不存在则新增
            UserMapping userMapping = data.SsoUserId > 0 ? siteContext.UserMapping.FirstOrDefault(x => x.SsoUserId == data.SsoUserId && (x.SourceSiteConfigId == siteConfig.Id || x.SourceSiteConfigId == tagerSiteConfig.Id))
                    : siteContext.UserMapping.FirstOrDefault(x => x.UserId == data.UserId && x.SourceSiteConfigId == siteConfig.Id);
            if (userMapping == null)
            {
                //#TODO 需要事物控制,如果回调认证失败,需要回滚
                userMapping = new UserMapping()
                {
                    UserId             = data.UserId,
                    SourceSiteConfigId = siteConfig.Id,
                    TargetSiteConfigId = tagerSiteConfig.Id,
                    Token = Guid.NewGuid()
                };
                siteContext.UserMapping.Add(userMapping);
                siteContext.SaveChanges();

                //#TODO 去 client 获取用户基本信息
                var user = new User()
                {
                    SsoUserId = userMapping.SsoUserId
                };
                siteContext.User.Add(user);
                siteContext.SaveChanges();
                #region 回调验证
                var callBackRequest = new AuthCallbackRequestModel()
                {
                    AuthType  = AuthTypeEnum.RedirectToSite,
                    SsoUserId = userMapping.SsoUserId,
                    UserId    = userMapping.UserId
                };
                var postData        = JsonConvert.SerializeObject(callBackRequest);
                var resrponseStr    = httpPostHelper.Send(siteConfig.AuthCallBack, siteConfig, postData);
                var reswponseObject = JsonConvert.DeserializeObject <AuthCallbackResponseModel>(resrponseStr);
                if (reswponseObject == null || !reswponseObject.Success)
                {
                    return(new AuthRedirectToSiteResponseModel()
                    {
                        Success = false,
                        Code = 4,
                        Message = "AuthCallback wrong."
                    });
                }
                #endregion
            }
            #endregion

            return(new AuthRedirectToSiteResponseModel()
            {
                Success = true,
                Code = 0,
                UserToken = userMapping.Token.ToString()
            });
        }