Example #1
0
        private String OnLogin(OAuthClient client, String state, String returnUrl)
        {
            var prov     = Provider;
            var redirect = prov.GetRedirect(Request, "~/Sso/LoginInfo/" + client.Name);
            // 请求来源,前后端分离时传front-end,重定向会带上token放到锚点
            var source = GetRequest("source");
            //if (state.IsNullOrEmpty() && !returnUrl.IsNullOrEmpty()) state = $"r={returnUrl}";
            //if (!source.IsNullOrEmpty())
            //{
            //    state += (state.IsNullOrEmpty() ? "" : "&") + $"s={source}";
            //}
            //state = HttpUtility.UrlEncode(state);

            var log = new OAuthLog
            {
                Provider     = client.Name,
                Action       = "Login",
                Success      = false,
                ResponseType = client.ResponseType,
                Scope        = client.Scope,
                State        = state,
                RedirectUri  = returnUrl,
                Source       = source
            };

            log.Insert();

            return(client.Authorize(redirect, log.Id + ""));
        }
Example #2
0
        /// <summary>绑定</summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public virtual ActionResult Bind(String id)
        {
            var prov = Provider;

            var user = prov.Current;

            if (user == null)
            {
#if __CORE__
                var returnUrl = Request.GetEncodedPathAndQuery();
#else
                var returnUrl = Request.Url?.PathAndQuery;
#endif
                var rurl = "~/Admin/User/Login".AppendReturn(returnUrl);
                return(Redirect(rurl));
            }

            var url    = prov.GetReturnUrl(Request, true);
            var client = prov.GetClient(id);
            client.Init(GetUserAgent());

            var redirect = prov.GetRedirect(Request, "~/Sso/LoginInfo/" + client.Name);

            var log = new OAuthLog
            {
                Provider     = client.Name,
                Action       = "Bind",
                Success      = false,
                ResponseType = client.ResponseType,
                Scope        = client.Scope,
                State        = null,
                RedirectUri  = url,
            };
            log.Insert();

            url = client.Authorize(redirect, log.Id + "");

            return(Redirect(url));
        }
Example #3
0
        /// <summary>登录后绑定当前用户</summary>
        public virtual OAuthLog BindAfterLogin(Int64 oauthId)
        {
            var prv  = Provider;
            var mode = nameof(BindAfterLogin);

            var user = prv.Current;

            if (user == null)
            {
                return(null);
            }

            var log = OAuthLog.FindById(oauthId);

            if (log == null)
            {
                return(null);
            }

            var uc = UserConnect.FindByID(log.ConnectId);

            if (uc == null)
            {
                return(null);
            }

            uc.UserID     = user.ID;
            uc.Enable     = true;
            uc.UpdateTime = DateTime.Now;
            uc.Update();

            log.UserId = user.ID;
            log.SaveAsync();

            // 写日志
            LogProvider.Provider?.WriteLog(typeof(User), "绑定", true, $"[{user}]依据[{mode}]绑定到[{uc.Provider}]的[{uc.NickName}]", user.ID, user + "");

            return(log);
        }
Example #4
0
        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;
            }
        }