Asp.net單點登入解決方案
吳劍 2009-06-24
原創文章,轉載必需註明出處:http://www.cnblogs.com/wu-jian
前言
本文為09年寫的一篇老文章,詳細介紹了單點登入(SSO)的設計、流程、實現關鍵點,以及Asp.net代碼示範。最近閑暇將文章進行了整理,重畫了UML,重寫了DEMO中的代碼。作為學習備忘,如能給人予協助,不甚榮幸。同時個人能力有限,文中不足之處還請及時指正。
為方便描述,首先定義幾個統一名詞,文中出現之處均為如下含義。
主站:Passport集中驗證伺服器,DEMO中為:http://www.passport.com/
分站:http://www.a.com/、http://www.b.com/、http://www.c.com/
憑證:使用者登入後產生的鑒權標識,用於識別授權使用者。可為多種方式,DEMO中主站使用的是Cache,分站使用的是Session。
令牌:由Passport頒發可在各分站中流通的使用者唯一鑒權標識,DEMO中使用的是Cookie。
核心邏輯
使用集中式身分識別驗證,使用者資料存放於Passport,各分站統一使用Passport進行登入和鑒權,如<圖1>所示:
<圖1>
<圖2>
<圖2>詳細描述了單點登入邏輯與流程
流程一:匿名使用者存取分站a
匿名使用者存取分站a上的一個授權頁面,首先跳轉到主站通過帳號、密碼進行登入鑒權,驗證通過後產生主站憑證,同時產生令牌,跳回分站a。
此時分站a檢測到使用者已持有令牌,於是用令牌再次去主站擷取使用者憑證,擷取成功後允許使用者訪問該授權頁面。同時產生分站a的本地憑證。
當該使用者需要再次驗證時將使用本地憑證,以減少網路互動。
流程二:在分站a登入的使用者訪問分站b
因為使用者在分站a登入過,已持有令牌,所以分站b會用令牌去主站擷取使用者憑證,擷取成功後允許使用者訪問授權頁面。同時產生分站b的本地憑證。
實現關鍵點
令牌
令牌由主站頒發,主站頒發令牌同時產生使用者憑證,並記錄令牌與使用者憑證之間的對應關係,以根據使用者提供的令牌響應對應的憑證;
令牌要在各跨域分站中進行流通,DEMO中使用了Cookie,並指定Cookie.Domain="passport.com";
各分站如何共用主站的Cookie?從分站Redirect到主站頁面,然後該頁面讀取Cookie並以URL參數方式回傳即可,可在DEMO代碼中查看詳細實現。
//產生令牌HttpCookie tokenCookie = new HttpCookie("Passport.Token");tokenCookie.Domain = "passport.com";//可使用自訂演算法避免Cookie非法複製//tokenCookie.Values.Add("Key", "密碼編譯演算法");tokenCookie.Values.Add("Value", tokenValue);Response.AppendCookie(tokenCookie);
在之前的文章中有讀者提到令牌(Cookie)被非法複製導致的安全問題,在此簡單說明一下。
首先預設設定了Cookie為關閉瀏覽器即失效,也就是說使用者在成功鑒權後持續開啟瀏覽器的前提下才會導至令牌泄漏。
然後在Passport令牌的設計中有“到期時間”一項,也可以通過使用令牌的到期時間來確保令牌安全。
如果您覺得還不夠,其實只需要在令牌驗證時添加一些自訂邏輯,比如用時間、使用者特徵產生一個Hash值作為令牌的安全KEY。
文章主要針對SSO的邏輯,一些細節上的代碼並未十全十美,讀者可以根據實際需求進行完善。
主站憑證
主站憑證是一個關係表,包含了三個欄位:令牌、使用者憑證、到期時間。
主站憑證有多種實現方式可供選擇,比如要求可靠的話可以使用資料庫,要求效能的話可以使用Cache,DEMO中我使用的是Cache。如下代碼所示:
/// <summary>/// 初始化快取資料結構/// </summary>/// <remarks>/// ----------------------------------------------------/// | token(令牌) | cert(使用者憑證) | timeout(到期時間) |/// |--------------------------------------------------|/// </remarks>private static void cacheInit(){ if (HttpContext.Current.Cache["PASSPORT.TOKEN"] == null) { DataTable dt = new DataTable(); dt.Columns.Add("token", Type.GetType("System.String")); dt.Columns["token"].Unique = true; dt.Columns.Add("cert", Type.GetType("System.Object")); dt.Columns["cert"].DefaultValue = null; dt.Columns.Add("timeout", Type.GetType("System.DateTime")); dt.Columns["timeout"].DefaultValue = DateTime.Now.AddMinutes(double.Parse(System.Configuration.ConfigurationManager.AppSettings["Timeout"])); DataColumn[] keys = new DataColumn[1]; keys[0] = dt.Columns["token"]; dt.PrimaryKey = keys; //Cache的到期時間為 令牌到期時間*2 HttpContext.Current.Cache.Insert("PASSPORT.TOKEN", dt, null, DateTime.MaxValue, TimeSpan.FromMinutes(double.Parse(System.Configuration.ConfigurationManager.AppSettings["Timeout"]) * 2)); }}
分站憑證
分站憑證主要用於減少重複驗證時網路的互動,比如使用者已在分站a上登入過,當他再次訪問分站a時,就不必使用令牌去主站驗證了,因為分站a已有該使用者的憑證。
分站憑證相對比較簡單,使用Session、Cookie均可。
分站SSO頁面基類
分站使用SSO的頁面會做一系列的邏輯判斷處理,如<圖2>所示。如果為每個頁面寫一遍這樣的邏輯會非常繁瑣。OK,那麼把這套邏輯封裝成一個基類,凡是要使用SSO的頁面繼承該基類即可。如下代碼所示:
public class AuthBase : System.Web.UI.Page{ protected override void OnLoad(EventArgs e) { if (Session["A.Cert"] != null) { //分站憑證存在 Response.Write("恭喜,分站憑證存在,您被授權訪問該頁面!"); } else { //令牌驗證結果返回 if (Request.QueryString["token"] != null) { //持有令牌 if (Request.QueryString["token"] != "$token$") { string tokenValue = Request.QueryString["token"]; //調用WebService擷取主站憑證 //防止令牌偽造 //此處還可使用公開金鑰私密金鑰的非對稱式加密策略 SSO.SiteA.ServiceReference1.PassportServiceSoapClient passportService = new SSO.SiteA.ServiceReference1.PassportServiceSoapClient(); object cert = passportService.TokenGetCert(tokenValue); if (cert != null) { //令牌正確 Session["A.Cert"] = cert; Response.Write("恭喜,令牌存在,您被授權訪問該頁面!"); } else { //令牌錯誤,去Passport登入 Response.Redirect(SSO.Common.Tools.TokenReplace()); } } //未持有令牌,去Passport登入 else { Response.Redirect(SSO.Common.Tools.TokenReplace()); } } //未進行令牌驗證,去Passport驗證 else { //當前url附加上token參數 Response.Redirect(SSO.Common.Tools.TokenUrl()); } } base.OnLoad(e); }}//end class
使用者退出
<圖3>
使用者退出時分別清空主站令牌/憑證與所有分站憑證。DEMO中通過調用WebService清空該使用者的主站令牌/憑證,通過iframe清空各分站憑證,請參閱DEMO中的詳細代碼實現。
主站到期令牌/憑證清除
讀者可自行實現該邏輯,定時清除(DataTable)Cache[“PASSPORT.TOKEN”]中timeout欄位超過目前時間的記錄。
DEMO
DEMO開發環境
.Net Framework 4.0
Visual Studio 2012
在IIS中配置網站
配置4個網站指向相應的目錄,並分別指定4個網站的主機頭:
http://www.passport.com/
http://www.a.com/
http://www.b.com/
http://www.c.com/
修改hosts檔案以將網域名稱解析到本地網站
127.0.0.1 http://www.passport.com/
127.0.0.1 http://www.a.com/
127.0.0.1 http://www.b.com/
127.0.0.1 http://www.c.com/
DEMO下載
http://files.cnblogs.com/wu-jian/wujian_sso.rar
<全文完>
作者:吳劍
出處:http://www.cnblogs.com/wu-jian/
本文著作權歸作者和部落格園共有,歡迎轉載,但必需註明出處,並且在文章頁面明顯位置給出原文串連,否則保留追究法律責任的權利。