zoukankan      html  css  js  c++  java
  • SSO集成方案[随笔]

    看这个方案之前,先说明下为什么要加入SSO,以防对大家产生不好的影响。我们产品使用传统winform+db服务+Db存储方式开发,一群老菜帮子开发,以传统的datatble做数据传递,很多年了未有变化。

    然后我来了,感觉我这个老菜帮子都受不了这种开发,然后下定决心,作了一些封装,看起来有点像orm的感觉了,并决定加入嵌入bs页面,美化界面,并补充winform在图表功能方面的短板。

    然后就造成了各BS模块分别嵌入到CS不同的页面中,并且各BS模块中有涉及到对业务的操作。很危险!因为在网页中可以直接打开各BS模块视图,无需登录,无需验证等。针对这种情况,SSO需求由此而来…

    目标:

      1.BS模块统一使用单点登录,不能没有限制就使用业务系统

      2.CS端嵌入BS时自动模拟SSO,实现可以免登录使用页面

     

    下文SSO科普是复制不知道谁的博文的,具体是谁忘了,在此说明下

    SSO整体流程图:

     

     

    SSO分为SSO-ServerSSO-Client两个部分,SSO-Client可以是多个的,即各个需要单点登录的client

    SSO-Server

    SSO-Server主要负责用户登录、注销、为SSO-Client分配token、验证token的工作。

    SSO-Server分配Token

    为SSO-Client分配Token的部分,在SSO-Client请求SSO受信页面的时候,检查SSO-Server是否登录,如果没有登录则跳转到SSO-Server的登录页面,如果已登录,则执行分配Token的代码,在分配完成以后将TokenID作为参数添加到returnUrl中,并跳转到returnUrl。

    当完成Token分配之后,页面将带有Token的参数跳转到SSO-Client页面,并在SSO-Client的Cookie中添加Token值,在以后的每次请求中,SSO-Client通过调用SSO-Server的服务来验证Token的合法性。

    ValidateToken用来验证TokenID的合法性,KeepToken用来保持Token不会过期。

    SSO-Client通过调用Validate验证Token,并得到当前的登录用户信息。

    SSO-Client

    SSO-Client作为受信系统来存在的,它自己没有认证系统,只能通过SSO-Server来完成用户身份认证的工作。

    当用户请求SSO-Client的受保护资源时,SSO-Client会首先是否有TokenID,如果存在TokenID,则调用SSO-Server的接口来验证这个TokenID是否合法;

    验证成功以后将会返回SSOToken的实例,里面包含已登录的用户信息

     

    科普后动手:

    MVC.SSO.Service:MVC+Redis,MVC实现SSO-Server的所有功能,存储和时效使用Redis管理,并使用Redis共享Session

    主要代码:

         /// <summary>
            /// 验证是否包含该token,并返回信息
            /// </summary>
            /// <param name="key"></param>
            /// <returns></returns>
            [HttpPost]
            public string ValidateToken(string key)
            {
                //var token = TokensManager.GetToken(key);
    
                try
                {
                    MyToken token = new MyToken();
                    token.ValidateToken = false;
    
                    if (BoolValidateToken(key))
                    {
                        token.User = redis.StringGet<USERS>(key);
                        token.ValidateToken = true;
                    }
    
                    return JsonConvert.SerializeObject(token);
                }
                catch (Exception ex)
                {
                    throw new Exception("ValidateToken:" + ex.Message);
                }
            }
    
    
         /// <summary>
            /// 登录
            /// </summary>
            /// <param name="name"></param>
            /// <param name="passWord"></param>
            /// <param name="backUrl"></param>
            /// <returns></returns>
            [HttpPost]
            public string Login(string name, string passWord, string backUrl)
            {
                try
                {
                    MyMsg msg = new MyMsg();
                    //tokenKey
                    byte[] byts = System.Text.Encoding.Default.GetBytes(string.Format("{0},{1}", name, passWord));
                    var key = Convert.ToBase64String(byts);
                    //判断是否TokenIds是否已存在该用户,不存在则判断登录,添加到token
                    if (!BoolValidateToken(key))
                    {
                        var user = userBll.GetUser(name, passWord);
                        if (user == null)
                        {
                            msg.IsLogined = false;
                            msg.Msg = "用户名或密码错误,登录失败!";
                        }
                        msg.IsLogined = true;
                        //并添加到全局变量中
                        //TokensManager.AddToken(key, user);
                        Session["Token"] = key;
                        redis.StringSet<USERS>(key, user);
                    }
    
                    Session["Token"] = key;
                    Response.Cookies.Add(new HttpCookie("cToken", key));
                    if (!string.IsNullOrEmpty(backUrl))
                    {
                        var url = backUrl + "?token=" + key;
                        //Response.Redirect(backUrl + "?token=" + key, true);//生成一个tokenId 发放到客户端
                        msg.BackUrl = url;
                    }
                    msg.Msg = "欢迎您:" + name;
                    return JsonConvert.SerializeObject(msg);
                }
                catch (Exception ex)
                {
                    throw;
                }
            }

    BS端MVC-Client集成方案

    MVC集成SSO方式为添加过滤器,并在需要添加SSO验证的控制器上添加上该过滤器

    主要代码:

    public override void OnActionExecuting(ActionExecutingContext filterContext)
            {
                base.OnActionExecuting(filterContext);
    
                try
                {
                    bool isLogined = false;//登录标志
                    var cToken = filterContext.HttpContext.Request.Cookies["cToken"];
                    var token = filterContext.HttpContext.Request["token"];
                    var sessionKey = HttpContext.Current.Session["Token"];
                    if (token != null || sessionKey != null || cToken != null)
                    {//eWFuc2hpLGE=
                        token = token ?? sessionKey.ToString() ?? cToken.Value;
                        var data = new { key = token };
                        //如果token不为空则去服务验证token是否有效
                        HttpContent httpContent = new StringContent(JsonConvert.SerializeObject(data));
                        httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
                        var httpClient = new HttpClient();
                        var responseJson = httpClient.PostAsync(SSOURL + "/ValidateToken", httpContent)
                            .Result.Content.ReadAsStringAsync().Result;
                        var myToken = JsonConvert.DeserializeObject<JH_OEMR_Model.MyToken>(responseJson);
                        if (myToken.ValidateToken)
                        {
                            isLogined = true;
                        }
                    }
    
                    if (!isLogined)
                        filterContext.HttpContext.Response.Redirect(SSOURL+"?backUrl=" + filterContext.HttpContext.Request.Url, true);
                }
                catch (Exception ex)
                {
                    filterContext.HttpContext.Response.Write("aaaaa"+ex.Message.ToString());
                    throw;
                }
            }

    CS端集成SSO:

    CS端加载BS页面时,先判断是否模拟登录,如未登录,模拟登录,然后访问BS端网址带上token即可

    主要代码:

    private static void LoginSSO()
            {
                var data = new { name = UName, passWord = UPwd, backUrl = string.Empty };
                HttpContent httpContent = new StringContent(JsonConvert.SerializeObject(data));
                httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
                var httpClient = new HttpClient();
                var responseJson = httpClient.PostAsync(SSOURL+"/Login", httpContent)
                    .Result.Content.ReadAsStringAsync().Result;
                var myToken = JsonConvert.DeserializeObject<MyMsg>(responseJson);
                if (myToken.IsLogined)
                {
                    IsLoginedSSO = true;
                }
            }
  • 相关阅读:
    Antd表格跨行
    Echarts使用记录
    PAT甲级刷题实录——1010
    PAT甲级刷题实录——1009(写文章时又想到了改进方法)
    PAT甲级刷题实录——1008
    PAT甲级刷题实录——1007
    PAT甲级刷题实录——1006
    PAT甲级刷题实录——1005
    PAT甲级刷题实录——1004
    PAT甲级刷题实录——1003
  • 原文地址:https://www.cnblogs.com/sy-ds/p/10696218.html
Copyright © 2011-2022 走看看