public ActionResult Index() { #if __CORE__ var user = ManagerProviderHelper.TryLogin(_provider, HttpContext.RequestServices); #else var user = ManageProvider.Provider.TryLogin(); #endif if (user == null) { return(RedirectToAction("Login", "User", new { #if __CORE__ r = Request.GetEncodedPathAndQuery() #else r = Request.Url.PathAndQuery #endif }));
public virtual ActionResult LoginInfo(String id, String code, String state) { if (id.IsNullOrEmpty()) { throw new ArgumentNullException(nameof(id)); } var name = id; var prov = Provider; var client = prov.GetClient(name); client.Init(GetUserAgent()); client.WriteLog("LoginInfo name={0} code={1} state={2} {3}", name, code, state, Request.GetRawUrl()); //var ds = state.SplitAsDictionary("=", "&"); var log = OAuthLog.FindById(state.ToLong()); if (log == null) { throw new InvalidOperationException("无效state=" + state); } //// 无法拿到code时,跳回去再来 //if (code.IsNullOrEmpty()) //{ // if (state == "refresh") throw new Exception("非法请求,无法取得code"); // return Redirect(OnLogin(client, $"{name}_refresh", null)); //} //// 短期内用过的code也跳回 //if (!_codeCache.TryAdd(code, code, false, out _)) //{ // return Redirect(OnLogin(client, $"{name}_refresh", null)); //} // 构造redirect_uri,部分提供商(百度)要求获取AccessToken的时候也要传递 var redirect = prov.GetRedirect(Request, "~/Sso/LoginInfo/" + client.Name); client.Authorize(redirect); //var returnUrl = prov.GetReturnUrl(Request, false); //var returnUrl = ds["r"]; var returnUrl = log.RedirectUri; try { // 获取访问令牌 if (!client.AccessUrl.IsNullOrEmpty()) { var html = client.GetAccessToken(code); // 如果拿不到访问令牌或用户信息,则重新跳转 if (client.AccessToken.IsNullOrEmpty() && client.OpenID.IsNullOrEmpty() && client.UserID == 0 && client.UserName.IsNullOrEmpty()) { XTrace.WriteLine("[{2}]拿不到访问令牌 code={0} state={1}", code, state, id); XTrace.WriteLine(Request.GetRawUrl() + ""); if (!html.IsNullOrEmpty()) { XTrace.WriteLine(html); } log.Success = false; log.Remark = html; throw new InvalidOperationException($"内部错误,无法获取令牌 code={code}"); } log.AccessToken = client.AccessToken; log.RefreshToken = client.RefreshToken; } //// 特殊处理钉钉 //if (client is DingTalkClient ding) DoDingDing(ding); // 获取OpenID。部分提供商不需要 if (!client.OpenIDUrl.IsNullOrEmpty()) { client.GetOpenID(); } // 短时间内不要重复拉取用户信息 // 注意,这里可能因为没有OpenID和UserName,无法判断得到用户链接,需要GetUserInfo后方能匹配UserConnect var set = Setting.Current; var uc = prov.GetConnect(client); if (uc.UpdateTime.AddSeconds(set.RefreshUserPeriod) < DateTime.Now) { // 获取用户信息 if (!client.UserUrl.IsNullOrEmpty()) { client.GetUserInfo(); } } // 如果前面没有取得用户链接,需要再次查询,因为GetUserInfo可能取得了UserName,而前面只有OpenId if (uc.ID == 0) { uc = prov.GetConnect(client); } uc.Fill(client); #if __CORE__ var url = prov.OnLogin(client, HttpContext.RequestServices, uc, log.Action == "Bind"); #else var url = prov.OnLogin(client, HttpContext, uc, log.Action == "Bind"); #endif log.ConnectId = uc.ID; log.UserId = uc.UserID; log.Success = true; log.Update(); // 标记登录提供商 Session["Cube_Sso"] = client.Name; // 如果验证成功但登录失败,直接跳走 if (url.IsNullOrEmpty()) { Session["Cube_OAuthId"] = log.Id; return(Redirect("/Admin/User/Login?autologin=0".AppendReturn(returnUrl))); } // 登录后自动绑定 var logId = Session["Cube_OAuthId"].ToLong(); if (logId > 0 && logId != log.Id) { Session["Cube_OAuthId"] = null; var log2 = Cube.Controllers.SsoController.Provider.BindAfterLogin(logId); if (log2 != null && log2.Success && !log2.RedirectUri.IsNullOrEmpty()) { return(Redirect(log2.RedirectUri)); } } if (!returnUrl.IsNullOrEmpty()) { url = returnUrl; } // 子系统颁发token给前端 if (log.Source == "front-end") { var jwt = ManagerProviderHelper.GetJwt(); jwt.Expire = DateTime.Now.Add(TimeSpan.FromHours(2)); jwt.Subject = uc.User.Name; var token = jwt.Encode(null); url += $"#token={token}"; } return(Redirect(url)); } catch (Exception ex) { if (log.Remark.IsNullOrEmpty()) { log.Remark = ex.ToString(); } log.Success = false; log.SaveAsync(); XTrace.WriteException(ex); throw; } }
/// <summary>登录成功</summary> /// <param name="client">OAuth客户端</param> /// <param name="context">服务提供者。可用于获取HttpContext成员</param> /// <returns></returns> public virtual String OnLogin(OAuthClient client, IServiceProvider context) { var openid = client.OpenID; if (openid.IsNullOrEmpty()) { openid = client.UserName; } // 根据OpenID找到用户绑定信息 var uc = UserConnect.FindByProviderAndOpenID(client.Name, openid); if (uc == null) { uc = new UserConnect { Provider = client.Name, OpenID = openid } } ; uc.Fill(client); // 强行绑定,把第三方账号强行绑定到当前已登录账号 var forceBind = false; #if __CORE__ var httpContext = context.GetService <IHttpContextAccessor>().HttpContext; var req = httpContext.Request; #else var req = context.GetService <HttpRequest>(); #endif if (req != null) { forceBind = req.Get("sso_action").EqualIgnoreCase("bind"); } // 可能因为初始化顺序的问题,导致前面没能给Provider赋值 var prv = Provider; if (prv == null) { prv = Provider = ManageProvider.Provider; } // 检查绑定,新用户的uc.UserID为0 var user = prv.FindByID(uc.UserID); if (forceBind || user == null || !uc.Enable) { user = OnBind(uc, client); } // 填充昵称等数据 Fill(client, user); if (user is IAuthUser user3) { user3.Logins++; user3.LastLogin = DateTime.Now; user3.LastLoginIP = WebHelper.UserHost; user3.Save(); } try { uc.Save(); } catch (Exception ex) { //为了防止某些特殊数据导致的无法正常登录,把所有异常记录到日志当中。忽略错误 XTrace.WriteException(ex); } if (!user.Enable) { throw new InvalidOperationException("用户已禁用!"); } // 登录成功,保存当前用户 //prv.Current = user; prv.SetCurrent(user, context); // 单点登录不要保存Cookie,让它在Session过期时请求认证中心 //prv.SaveCookie(user); var set = Setting.Current; if (set.SessionTimeout > 0) #if __CORE__ { ManagerProviderHelper.SaveCookie(prv, user, TimeSpan.FromSeconds(set.SessionTimeout), httpContext); } #else { prv.SaveCookie(user, TimeSpan.FromSeconds(set.SessionTimeout), context); } #endif return(SuccessUrl); }
/// <summary>登录成功</summary> /// <param name="client">OAuth客户端</param> /// <param name="context">服务提供者。可用于获取HttpContext成员</param> /// <returns></returns> public virtual String OnLogin(OAuthClient client, IServiceProvider context, UserConnect uc) { // 强行绑定,把第三方账号强行绑定到当前已登录账号 var forceBind = false; #if __CORE__ var httpContext = context.GetService <IHttpContextAccessor>().HttpContext; var req = httpContext.Request; var ip = httpContext.GetUserHost(); #else var req = context.GetService <HttpRequest>(); var ip = req.RequestContext.HttpContext.GetUserHost(); #endif //if (req != null) forceBind = req.Get("sso_action").EqualIgnoreCase("bind"); if (req != null) { forceBind = req.Get("state").EndsWithIgnoreCase("_bind"); } // 可能因为初始化顺序的问题,导致前面没能给Provider赋值 var prv = Provider; if (prv == null) { prv = Provider = ManageProvider.Provider; } // 检查绑定,新用户的uc.UserID为0 var user = prv.FindByID(uc.UserID); if (forceBind || user == null || !uc.Enable) { user = OnBind(uc, client); } // 填充昵称等数据 Fill(client, user); if (user is IAuthUser user3) { user3.Logins++; user3.LastLogin = DateTime.Now; user3.LastLoginIP = ip; //user3.Save(); //(user3 as IEntity).Update(); } if (user is IEntity entity) { entity.Update(); } try { uc.UpdateTime = DateTime.Now; uc.Save(); } catch (Exception ex) { //为了防止某些特殊数据导致的无法正常登录,把所有异常记录到日志当中。忽略错误 XTrace.WriteException(ex); } // 写日志 var log = LogProvider.Provider; log?.WriteLog(typeof(UserX), "SSO登录", true, $"[{user}]从[{client.Name}]的[{client.UserName}]登录", user.ID, user + ""); if (!user.Enable) { throw new InvalidOperationException($"用户[{user}]已禁用!"); } // 登录成功,保存当前用户 //prv.Current = user; prv.SetCurrent(user, context); // 单点登录不要保存Cookie,让它在Session过期时请求认证中心 //prv.SaveCookie(user); var set = Setting.Current; if (set.SessionTimeout > 0) #if __CORE__ { ManagerProviderHelper.SaveCookie(prv, user, TimeSpan.FromSeconds(set.SessionTimeout), httpContext); } #else { prv.SaveCookie(user, TimeSpan.FromSeconds(set.SessionTimeout), context); } #endif return(SuccessUrl); }
public virtual ActionResult LoginInfo(String id, String code, String state) { if (id.IsNullOrEmpty()) { throw new ArgumentNullException(nameof(id)); } var name = id; var prov = Provider; var client = prov.GetClient(name); client.Init(GetUserAgent()); client.WriteLog("LoginInfo name={0} code={1} state={2} {3}", name, code, state, Request.GetRawUrl()); var ds = state.SplitAsDictionary("=", "&"); //// 无法拿到code时,跳回去再来 //if (code.IsNullOrEmpty()) //{ // if (state == "refresh") throw new Exception("非法请求,无法取得code"); // return Redirect(OnLogin(client, $"{name}_refresh", null)); //} //// 短期内用过的code也跳回 //if (!_codeCache.TryAdd(code, code, false, out _)) //{ // return Redirect(OnLogin(client, $"{name}_refresh", null)); //} // 构造redirect_uri,部分提供商(百度)要求获取AccessToken的时候也要传递 var redirect = prov.GetRedirect(Request, "~/Sso/LoginInfo/" + client.Name); client.Authorize(redirect); //var returnUrl = prov.GetReturnUrl(Request, false); var returnUrl = ds["r"]; try { // 获取访问令牌 if (!client.AccessUrl.IsNullOrEmpty()) { var html = client.GetAccessToken(code); // 如果拿不到访问令牌或用户信息,则重新跳转 if (client.AccessToken.IsNullOrEmpty() && client.OpenID.IsNullOrEmpty() && client.UserID == 0 && client.UserName.IsNullOrEmpty()) { XTrace.WriteLine("[{2}]拿不到访问令牌 code={0} state={1}", code, state, id); XTrace.WriteLine(Request.GetRawUrl() + ""); if (!html.IsNullOrEmpty()) { XTrace.WriteLine(html); } throw new InvalidOperationException($"内部错误,无法获取令牌 code={code}"); } } //// 特殊处理钉钉 //if (client is DingTalkClient ding) DoDingDing(ding); // 获取OpenID。部分提供商不需要 if (!client.OpenIDUrl.IsNullOrEmpty()) { client.GetOpenID(); } // 短时间内不要重复拉取用户信息 // 注意,这里可能因为没有OpenID和UserName,无法判断得到用户链接,需要GetUserInfo后方能匹配UserConnect var set = Setting.Current; var uc = prov.GetConnect(client); if (uc.UpdateTime.AddSeconds(set.RefreshUserPeriod) < DateTime.Now) { // 获取用户信息 if (!client.UserUrl.IsNullOrEmpty()) { client.GetUserInfo(); } } // 如果前面没有取得用户链接,需要再次查询 if (uc.ID == 0) { uc = prov.GetConnect(client); } uc.Fill(client); #if __CORE__ var url = prov.OnLogin(client, HttpContext.RequestServices, uc, ds["a"] == "bind"); #else var url = prov.OnLogin(client, HttpContext, uc, ds["a"] == "bind"); #endif // 标记登录提供商 Session["Cube_Sso"] = client.Name; if (!returnUrl.IsNullOrEmpty()) { url = returnUrl; } // 子系统颁发token给前端 if (state == "front-end") { var jwt = ManagerProviderHelper.GetJwt(); jwt.Expire = DateTime.Now.Add(TimeSpan.FromHours(2)); jwt.Subject = uc.User.Name; var token = jwt.Encode(null); url += $"#token={token}"; } return(Redirect(url)); } catch (Exception ex) { XTrace.WriteException(ex.GetTrue()); throw; } }