基于.Net的單點登錄(SSO)解決方案
????? 閑話少敘,進入正題,我的想法是使用集中驗證方式,多個站點集中Passport驗證。?如下圖所示:

????? 為方便清晰描述,先定義幾個名詞,本文中出現之處均為如下含義。
?????
主站
:Passport集中驗證服務器
http://www.passport.com/
。
?????
分站
:
http://www.a.com/
、
http://www.b.com/
、
http://www.c.com/
?
??????
憑證
:用戶登錄后產生的數據標識,用于識別授權用戶,可為多種方式,DEMO中主站我使用的是Cache,分站使用Session。
?????
令牌
:由Passport頒發可在各分站中流通的唯一標識。
????? OK,現在描述一下單點登錄的過程:
????? 情形一、匿名用戶:匿名用戶訪問分站a上的一個授權頁面,首先跳轉到主站讓用戶輸入帳號、密碼進行登錄,驗證通過后產生主站憑證,同時產生令牌,跳轉回分 站a,此時分站a檢測到用戶已持有令牌,于是用令牌再次去主站獲取用戶憑證,獲取成功后允許用戶訪問該授權頁面。同時產生分站a的本地憑證,當該用戶需要 再次驗證時將先檢查本地憑證,以減少網絡交互。
????? 情形二、在分站a登錄的用戶訪問分站b:因為用戶在分站a登錄過,已持有令牌,所以分站b會用令牌去主站獲取用戶憑證,獲取成功后允許用戶訪問授權頁面。同時產生分站b的本地憑證。
????? 設計完成后,接下來是方案實現的一些關鍵點:
????? 令牌
:令牌 由主站頒發,主站頒發令牌同時生成用戶憑證,并記錄令牌與用戶憑證之間的對應關系,以根據用戶提供的令牌響應對應的憑證;令牌要在各跨域分站中進行流通, 所以DEMO中令牌我使用主站的Cookie,并指定Cookie.Domain="passport.com"。各分站如何共享主站的Cookie?從 分站Redirect到主站頁面,然后該頁面讀取Cookie并以URL參數方式回傳即可,可在DEMO代碼中查看詳細實現,當然如果哪位有更好的令牌實 現方式也拿出來分享。
string ?tokenValue? = ?Guid.NewGuid().ToString().ToUpper();
HttpCookie?tokenCookie? = ? new ?HttpCookie( " Token " );
tokenCookie.Values.Add( " Value " ,?tokenValue);
tokenCookie.Domain? = ? " passport.com " ;
Response.AppendCookie(tokenCookie);?
????? 主站憑證
:主站憑證是一個關系表,包含了三個字段:令牌、憑證數據、過期時間。有多種實現方式可供選擇,要求可靠的話用數據庫,要求性能的話用Cache,DEMO中我使用的是Cache中的DataTable。如下代碼所示:
/// ?初始化數據結構
/// ? </summary>
/// ? <remarks>
/// ?----------------------------------------------------
/// ?|?token(令牌)?|?info(用戶憑證)?|?timeout(過期時間)?|
/// ?|--------------------------------------------------|
/// ? </remarks>
private ? static ? void ?cacheInit()
{
???? if ?(HttpContext.Current.Cache[ " CERT " ]? == ? null )
????{
????????DataTable?dt? = ? new ?DataTable();
????????dt.Columns.Add( " token " ,?Type.GetType( " System.String " ));
????????dt.Columns[ " token " ].Unique? = ? true ;
????????dt.Columns.Add( " info " ,?Type.GetType( " System.Object " ));
????????dt.Columns[ " info " ].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( " CERT " ,?dt,? null ,?DateTime.MaxValue,?TimeSpan.FromMinutes( double .Parse(System.Configuration.ConfigurationManager.AppSettings[ " timeout " ])? * ? 2 ));
????}
}
?
????? 分站憑證 :分站憑證主要用于減少重復驗證時網絡的交互,比如用戶已在分站a上登錄過,當他再次訪問分站a時,就不必使用令牌去主站驗證了,因為分站a已有該用戶的憑證。分站憑證相對比較簡單,使用Session、Cookie均可。
????? 分站SSO頁面基類 :分站使用SSO的頁面會做一系列的邏輯判斷處理,如文章開頭的流程圖。如果有多個頁面的話不可能為每個頁寫一個這樣的邏輯,OK,那么把這套邏輯封裝成一個基類,凡是要使用SSO的頁面繼承該基類即可。如下代碼所示:
using ?System.Data;
using ?System.Configuration;
using ?System.Web;
using ?System.Web.Security;
using ?System.Web.UI;
using ?System.Web.UI.WebControls;
using ?System.Web.UI.WebControls.WebParts;
using ?System.Web.UI.HtmlControls;
using ?System.Text.RegularExpressions;
namespace ?SSO.SiteA.Class
{
???? /// ? <summary>
???? /// ?授權頁面基類
???? /// ? </summary>
???? public ? class ?AuthBase?:?System.Web.UI.Page
????{
???????? protected ? override ? void ?OnLoad(EventArgs?e)
????????{
???????????? if ?(Session[ " Token " ]? != ? null )
????????????{
???????????????? // 分站憑證存在
????????????????Response.Write( " 恭喜,分站憑證存在,您被授權訪問該頁面! " );
????????????}
???????????? else
????????????{
???????????????? // 令牌驗證結果
???????????????? if ?(Request.QueryString[ " Token " ]? != ? null )
????????????????{
???????????????????? if ?(Request.QueryString[ " Token " ]? != ? " $Token$ " )
????????????????????{
???????????????????????? // 持有令牌
???????????????????????? string ?tokenValue? = ?Request.QueryString[ " Token " ];
???????????????????????? // 調用WebService獲取主站憑證
????????????????????????SSO.SiteA.RefPassport.TokenService?tokenService? = ? new ?SSO.SiteA.RefPassport.TokenService();
???????????????????????? object ?o? = ?tokenService.TokenGetCredence(tokenValue);
???????????????????????? if ?(o? != ? null )
????????????????????????{
???????????????????????????? // 令牌正確
????????????????????????????Session[ " Token " ]? = ?o;
????????????????????????????Response.Write( " 恭喜,令牌存在,您被授權訪問該頁面! " );
????????????????????????}
???????????????????????? else
????????????????????????{
???????????????????????????? // 令牌錯誤
????????????????????????????Response.Redirect( this .replaceToken());
????????????????????????}
????????????????????}
???????????????????? else
????????????????????{
???????????????????????? // 未持有令牌
????????????????????????Response.Redirect( this .replaceToken());
????????????????????}
????????????????}
???????????????? // 未進行令牌驗證,去主站驗證
???????????????? else
????????????????{
????????????????????Response.Redirect( this .getTokenURL());
????????????????}
????????????}
???????????? base .OnLoad(e);
????????}
???????? /// ? <summary>
???????? /// ?獲取帶令牌請求的URL
???????? /// ?在當前URL中附加上令牌請求參數
???????? /// ? </summary>
???????? /// ? <returns></returns>
???????? private ? string ?getTokenURL()
????????{
???????????? string ?url? = ?Request.Url.AbsoluteUri;
????????????Regex?reg? = ? new ?Regex( @" ^.*\?.+=.+$ " );
???????????? if ?(reg.IsMatch(url))
????????????????url? += ? " &Token=$Token$ " ;
???????????? else
????????????????url? += ? " ?Token=$Token$ " ;
???????????? return ? " http://www.passport.com/gettoken.aspx?BackURL= " ? + ?Server.UrlEncode(url);
????????}
???????? /// ? <summary>
???????? /// ?去掉URL中的令牌
???????? /// ?在當前URL中去掉令牌參數
???????? /// ? </summary>
???????? /// ? <returns></returns>
???????? private ? string ?replaceToken()
????????{
???????????? string ?url? = ?Request.Url.AbsoluteUri;
????????????url? = ?Regex.Replace(url,? @" (\?|&)Token=.* " ,? "" ,?RegexOptions.IgnoreCase);
???????????? return ? " http://www.passport.com/userlogin.aspx?BackURL= " ? + ?Server.UrlEncode(url);
????????}
????} // end?class
}
?
????? 用戶退出:
用戶退出時分別清空主站憑證與當前分站憑證。如果要求A站點退出,B、C站點也退出,可自行擴展接口清空每個分站憑證。
????? 主站過期憑證/令牌清除
:定時清除(DataTable)Cache[“CERT”]中timeout字段超過當前時間的記錄。
點擊此處下載DEMO
1. 在 IIS 中配置站點
配置 4 個站點指向相應的目錄,并分別指定 4 個站點的主機頭:
2. 修改 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/
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
