/// <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 }
/// <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)); }
/// <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() }); }