誰都能看懂的單點登入(SSO)實現方式(附原始碼)
SSO的基本概念
SSO英文全稱Single Sign On(單點登入)。SSO是在多個應用系統中,使用者只需要登入一次就可以訪問所有相互信任的應用系統。它包括可以將這次主要的登入對映到其他應用中用於同一個使用者的登入的機制。它是目前比較流行的企業業務整合的解決方案之一。(本段內容來自百度百科)
今天這篇文章將介紹SSO的一種實現方式,程式碼超簡單,僅用來驗證我的思路是否可行,具體細節請大家來完善!
二級域名的單點登入
什麼是二級域名呢?例如:
- site1.domain.com
- site2.domain.com
對於二級域名的單點登入,我們可以非常方便的通過共享cookie來實現,簡單的說,就是在設定Form票據的時候,將cookie的domain設定為頂級域名即可,例如:
HttpCookie cookie = new HttpCookie(FormsAuthCookieName, encryptedTicket); cookie.Expires = rememberMe ? expirationDate : DateTime.MinValue; cookie.HttpOnly = true; cookie.Path = "/"; cookie.Domain = "domain.com"; context.Response.Cookies.Set(cookie);
這種方式不涉及跨域,當cookie的domain屬性設定為頂級域名之後,所有的二級域名都可以訪問到身份驗證的cookie,在伺服器端只要驗證了這個cookie就可以實現身份的驗證。
但是,當跨域的時候,例如:
- site1.com
- site2.com
這個時候就不能共享cookie了,所以上面的解決方案就會失效。那麼,要實現跨域的單點登入該如何做呢?請繼續往下看。
跨域的單點登入
關於跨域的SSO的設計思路,我畫了一個簡單的流程圖:
首先,我將跨域的SSO分為SSO-Server和SSO-Client兩個部分,SSO-Client可以是多個的。
SSO-Server
SSO-Server主要負責使用者登入、登出、為SSO-Client分配taken、驗證taken的工作。
登入和登出採用的是Form認證方式,很多地方都有詳細的介紹,我之前也寫過一篇文章,想了解的可以去看看:
SSO-Server分配Token
為SSO-Client分配Token的部分,在SSO-Client請求SSO受信頁面的時候,檢查SSO-Server是否登入,如果沒有登入則跳轉到SSO-Server的登入頁面,如果已登入,則執行分配Token的程式碼,在分配完成以後將TokenID作為引數新增到returnUrl中,並跳轉到returnUrl,具體的分配程式碼如下:
if (Domain.Security.SmartAuthenticate.LoginUser != null) { //生成Token,並持久化Token Domain.SSO.Entity.SSOToken token = new Entity.SSOToken(); token.User = new Entity.SSOUser(); token.User.UserName = Domain.Security.SmartAuthenticate.LoginUser.UserName; token.LoginID = Session.SessionID; Domain.SSO.Entity.SSOToken.SSOTokenList.Add(token); //拼接返回的url,引數中帶Token string spliter = returnUrl.Contains('?') ? "&" : "?"; returnUrl = returnUrl + spliter + "token=" + token.ID; Response.Redirect(returnUrl); }
當完成Token分配之後,頁面將帶有TokenID的引數跳轉到SSO-Client頁面,並在SSO-Client的Cookie中新增Token值,在以後的每次請求中,SSO-Client通過呼叫SSO-Server的服務來驗證Token的合法性。
SSO-Server驗證Token
我是通過WebService來驗證Token的。
首先在SSO-Server定義一個Web Service:
[WebMethod] public Entity.SSOToken ValidateToken(string tokenID) { if (!KeepToken(tokenID)) return null; var token = Domain.SSO.Entity.SSOToken.SSOTokenList.Find(m => m.ID == tokenID); return token; } [WebMethod] public bool KeepToken(string tokenID) { var token = Domain.SSO.Entity.SSOToken.SSOTokenList.Find(m => m.ID == tokenID); if (token == null) return false; if (token.IsTimeOut()) return false; token.AuthTime = DateTime.Now; return true; }
ValidateToken用來驗證TokenID的合法性,KeepToken用來保持Token不會過期。
SSO-Client通過呼叫Validate驗證Token,並得到當前的登入使用者資訊。接下來看看SSO-Client的實現。
SSO-Client
SSO-Client作為受信系統來存在的,它自己沒有認證系統,只能通過SSO-Server來完成使用者身份認證的工作。
當用戶請求SSO-Client的受保護資源時,SSO-Client會首先是否有TokenID,如果存在TokenID,則呼叫SSO-Server的WebService來驗證這個TokenID是否合法;
驗證成功以後將會返回SSOToken的例項,裡面包含已登入的使用者資訊。具體程式碼如下:
if (!string.IsNullOrEmpty(tokenID)) { AuthTokenService.AuthTokenServiceSoapClient client = new AuthTokenService.AuthTokenServiceSoapClient(); var token = client.ValidateToken(tokenID); if (token != null) { this.lblMessage.Text = "登入成功,登入使用者:" + token.User.UserName + "<a href='http://sso-server.com/logout.aspx?returnUrl=" + Server.UrlEncode("http://sso-client.com") + "'>退出</a>"; } else { Response.Redirect("http://sso-server.com/sso.aspx?returnUrl=" + Server.UrlEncode("http://sso-client.com/default.aspx")); } } else { Response.Redirect("http://sso-server.com/sso.aspx?returnUrl=" + Server.UrlEncode("http://sso-client.com/default.aspx")); }
原始碼
文章中已經介紹了我的具體思路和一些實現,如果你仍然感興趣,可以下載我的程式碼>>Demo.SSO
原始碼的部署:
1. 在IIS中建立兩個站點,分別繫結到SSO-Server和SSO-Client,它們繫結的域名分別是sso-server.com和sso-client.com
2. 在hosts檔案中新增兩行對映,將sso-server.com和sso-client.com對映到127.0.0.1,確保可以訪問
3.訪問sso-client.com,這個時候頁面將跳轉到sso-server.com的登入頁面,使用者名稱、密碼隨便輸入,然後點選登入即可
我很認真的完成了這個方案,也感謝你很認真的看完!歡迎拍磚!
如果認為此文對您有幫助,別忘了支援一下哦!