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;
            }
        }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM