Exemplo n.º 1
0
        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
                }));
Exemplo n.º 2
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;
            }
        }
Exemplo n.º 3
0
        /// <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);
        }
Exemplo n.º 4
0
        /// <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);
        }
Exemplo n.º 5
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("=", "&");

            //// 无法拿到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;
            }
        }