隨著數(shù)字化的不斷普及,大型公式或者單位的各個部門逐漸的上了與本身業(yè)務(wù)相關(guān)的各種各樣的系統(tǒng)(在這些系統(tǒng)中,以Web系統(tǒng)居多),幾乎每個系統(tǒng)都 需要識別操作者的身份,并根據(jù)其不同的身份,分配一定的權(quán)限,做一些操作上的限制。結(jié)果很多公司或者部門都在各個系統(tǒng)便各自設(shè)計了一套用戶資料和權(quán)限管理 的機制,并提供了用戶登錄證認(rèn)。這樣滿足了上面的需求,但由此帶來和用戶賬號管理不方便,用戶資料不統(tǒng)一等等問題。在數(shù)字化網(wǎng)絡(luò)化發(fā)展到一定階段時,對用 戶資料的整合起來,進行統(tǒng)一的管理變得十分必要。
本文的目的在探討一個簡單有效的方案,將有一定聯(lián)系,擁有統(tǒng)一用戶群的系統(tǒng)進行關(guān)聯(lián),統(tǒng)一用戶的登錄資料,并提供統(tǒng)一的登錄認(rèn)證入口。統(tǒng)一認(rèn)證系統(tǒng) 與不同應(yīng)用子系統(tǒng)之間建立一定的信任關(guān)系,通過一定的渠道交換認(rèn)證信息,在保證用戶信息安全的基礎(chǔ)上,實現(xiàn)認(rèn)證關(guān)系的共享機制。使用戶一個地方一次登錄之 后,便可以在相應(yīng)的應(yīng)用系統(tǒng)群中遨游,而不用沒到一個系統(tǒng)就進行登錄,甚至使用不同的賬號和密碼進行登錄。
網(wǎng)站與用戶之間的認(rèn)證關(guān)系,我們一般通過Session來建立,而Session(一般)在不同網(wǎng)站中是不能共享的。本方案的難點在于統(tǒng)一認(rèn)證系統(tǒng) 和應(yīng)用子系統(tǒng)之間認(rèn)證信息的共享。用戶在統(tǒng)一認(rèn)證系統(tǒng)中登錄之后,與統(tǒng)一登錄系統(tǒng)建立了認(rèn)證關(guān)系,如果用戶轉(zhuǎn)向應(yīng)用子系統(tǒng),此時如何與子系統(tǒng)建立認(rèn)證關(guān) 系,如何將統(tǒng)一認(rèn)證系統(tǒng)的認(rèn)證關(guān)系遷移復(fù)制到子系統(tǒng),這將是我們要解決的問題。
ASP.NET的Session保存機制(會話狀態(tài)模式)有三種......
ASP.NET 支持三種會話狀態(tài)模式:
InProc:In-Proc 模式將值存儲在 ASP.NET 輔助進程的內(nèi)存中。因此,該模式提供了對這些值的最快訪問。但是,當(dāng) ASP.NET 輔助進程被回收時,狀態(tài)數(shù)據(jù)便會丟失。
StateServer:與上一模式不同,StateServer 模式使用獨立的 Microsoft Windows 服務(wù)來存儲會話變量。因為該服務(wù)獨立于 Microsoft Internet Information Server (IIS),所以它可以在另一獨立的服務(wù)器上運行。您可以將此模式用于負(fù)載平衡解決方案,因為多個 Web 服務(wù)器可共享會話變量。盡管在重新啟動 IIS 時會話變量不會丟失,但在跨越進程邊界時,性能會受到影響。
SqlServer:如果會話信息的持久性對于您很重要,那么您可以使用 SqlServer 模式,以便利用 Microsoft SQL Server 來確保達到最高級別的可靠性。SqlServer 模式類似于進程外模式,只是前者的會話數(shù)據(jù)維護在 SQL Server 中。SqlServer 模式還讓您能夠利用位于 IIS 進程外的一個狀態(tài)存儲區(qū),該狀態(tài)存儲區(qū)既可位于本地計算機上,也可位于遠程服務(wù)器上。
網(wǎng)站的默認(rèn)Session狀態(tài)模式應(yīng)該是InProc,限制了本系統(tǒng)網(wǎng)站使用。StateServer和SqlServer都作為擴展,將會話信息 存儲在IIS進程之外,實現(xiàn)了不同Web服務(wù)器之間的共享。當(dāng)然,這兩種模式都需要做相應(yīng)的配置和消耗一定的性能,我們暫且不說這一點。仔細(xì)研究發(fā)現(xiàn),這 兩種擴展模式主要面向的是網(wǎng)站的分流和負(fù)載均衡,共享Session的網(wǎng)站之間的結(jié)合是非常非常密切的,并且ASP.NET將所有的實現(xiàn)都進行了封裝,我 們無法獲取和記錄每一次共享的細(xì)節(jié)。這并不適合我們最開始的需求。
假設(shè):A系統(tǒng)通過Session保存了一個User實例,那么如果B系統(tǒng)需要使用這個Session,則必需擁有A系統(tǒng)中User的細(xì)節(jié)。如果A、 B兩個系統(tǒng)是完全不同,甚至其中不同細(xì)節(jié)User類,更甚至A、B系統(tǒng)中都不只一處功能使用到Session,Session的命名又總碰巧一致。呵呵, 那一切將變得不可思議。當(dāng)然,如果我A、B為統(tǒng)一個系統(tǒng)的兩個不同的應(yīng)用層,那StateServer和SqlServer這兩種方式將能夠很好的滿足需 求。至于要滿足我們上面的需求,只能是另外想辦法了。
尋找解決辦法,我們比較關(guān)系用戶體驗,那么先從用戶的使用流程開始.......
根據(jù)我們的需求,用戶的體驗一般有兩種:
一、對于使用多個子系統(tǒng)的用戶,將有可能直接登錄統(tǒng)一認(rèn)證系統(tǒng),并通過統(tǒng)一系統(tǒng)的子系統(tǒng)連接列表,跳轉(zhuǎn)到多個子系統(tǒng);二、對于一些使用單個子系統(tǒng), 或者自為單具體事情進入我們平臺,或者是登錄超時了,這是他應(yīng)該向直接進入特定子系統(tǒng),那么我們需要將登錄驗證在他進入子系統(tǒng)之前插入。兩種不同方式的三 個系統(tǒng)之間的交互過程如下圖所示:
圖 1. 一般步驟,同時登錄多個子系統(tǒng)
圖 2. 直接進入子系統(tǒng),子系統(tǒng)之間跳轉(zhuǎn)
我將按照第一種交互方式進行解釋:
1、用戶先與統(tǒng)一登錄系統(tǒng)進行交互,使用唯一的賬號密碼進行登錄,此時不涉及任何子系統(tǒng);
2、用戶登錄成功后,統(tǒng)一登錄系統(tǒng)將信任的應(yīng)用子系統(tǒng)列表呈現(xiàn)給用戶;
3、用戶根據(jù)需要,選擇子系統(tǒng)連接訪問子系統(tǒng),用戶與子系統(tǒng)的交互開始;
4、由于用戶與子系統(tǒng)此時還沒有建立認(rèn)證關(guān)系,所以子系統(tǒng)將用戶重定向到統(tǒng)一登錄系統(tǒng);
5、統(tǒng)一登錄系統(tǒng)驗證用戶的登錄信息,發(fā)現(xiàn)用戶已經(jīng)登錄,便將登錄信息插入到數(shù)據(jù)庫,再將驗證信息發(fā)給用戶,即返回一個等待頁面;
6、用戶將等待頁面中的驗證信息提交(自動)到子系統(tǒng),子系統(tǒng)獲取認(rèn)證信息;
7、子系統(tǒng)通過一定的辦法和等待頁面中的驗證信息進行驗證,并與用戶建立了信任關(guān)系;
與ASP.NET封裝的實現(xiàn)方案項目,這交互過程看起來十分煩碎,我們還需要自己實現(xiàn)大量的功能。但我們的交互實現(xiàn)過程都是可控的,各個系統(tǒng)之間傳 遞的信息內(nèi)容,什么時候傳遞,我能都可以限制和約定,并且能夠?qū)⒚恳淮蜗到y(tǒng)之間的交互記錄都進行登記,這才是我們需要的。至于煩碎,其實對用戶來說,增加 的步驟就是出現(xiàn)自動提交的等待登錄頁面,如果兩個系統(tǒng)都能正常運行,網(wǎng)絡(luò)也沒有出現(xiàn)堵塞,用戶等待的時間將及其短暫,甚至沒能看到頁面。并且我們能夠?qū)Φ?待頁面做一定的美化,使用戶就算看到等待頁面,也不會感到厭煩。
說了這么多,統(tǒng)一認(rèn)證系統(tǒng)的應(yīng)用子系統(tǒng)Session的共享還沒有開始,這是本方案最大的難點......
下面就簡述統(tǒng)一認(rèn)證系統(tǒng)的應(yīng)用子系統(tǒng)Session的共享的實現(xiàn),我和一位同事根據(jù)大伙的討論結(jié)果,分兩種方式進行實現(xiàn),詳細(xì)情況如下:
第一種方式:通過MD5加密隨機字符串,使用了Web服務(wù)實現(xiàn)了子系統(tǒng)和統(tǒng)一認(rèn)證系統(tǒng)之間的交互驗證。驗證信息包含兩部分用戶在統(tǒng)一登錄系統(tǒng)的Session ID和數(shù)據(jù)庫中的隨機ID。當(dāng)子系統(tǒng)將用戶重定向到統(tǒng)一登錄系統(tǒng)的時候,驗證的交互過程開始,詳細(xì)步驟如下:
1、統(tǒng)一登錄系統(tǒng)獲取用戶的Session ID和登錄名
2、統(tǒng)一登錄系統(tǒng)將Session ID和登錄名插入到數(shù)據(jù)庫,產(chǎn)生一個隨機的數(shù)據(jù)庫ID
3、將Session ID和數(shù)據(jù)庫ID結(jié)合起來,進行MD5加密
4、使用MD5密文和數(shù)據(jù)庫ID構(gòu)建一個登錄等待頁面,返回給用戶
5、用戶將登錄等待頁面中的信息自動提交給子系統(tǒng)
6、子系統(tǒng)通過Web服務(wù)將MD5密文和數(shù)據(jù)庫ID提交回統(tǒng)一登錄系統(tǒng)
7、統(tǒng)一登錄系統(tǒng)查詢數(shù)據(jù)庫,并進行驗證
8、統(tǒng)一登錄系統(tǒng)返回用戶登錄名,并刪除數(shù)據(jù)庫中的登錄記錄。
9、子系統(tǒng)與用戶建立認(rèn)證關(guān)系
圖 3. MD5隨機加密,Web服務(wù)實現(xiàn)驗證
第二種方式:通過對認(rèn)證信息(登錄令牌)進行非對稱加密,一次交互實現(xiàn)驗證。驗證信息為一個包含了產(chǎn)生時間的Token類。驗證的交互過程同樣是在重定向到統(tǒng)一登錄系統(tǒng)的時候開始,詳細(xì)步驟如下:
1、構(gòu)建一個包含生成時間的Token類,將Token類序列化
2、使用SHA-1,對序列化Token編碼進行散列,產(chǎn)生驗證碼H
3、將序列化Token編碼和驗證碼H結(jié)合,使用公鑰加密
4、使用密文構(gòu)建一個登錄等待頁面,返回給用戶
5、用戶將登錄等待頁面中的信息自動提交給子系統(tǒng)
6、子系統(tǒng)使用私鑰進行解密
7、子系統(tǒng)分離出散列驗證碼H和序列化Token編碼,并進行SHA-1驗證
8、檢查Token中的生成時間,判斷是否超時
9、子系統(tǒng)與用戶建立認(rèn)證關(guān)系
圖 4. 非對稱加密,一次交互實現(xiàn)驗證兩種方式各有優(yōu)缺點,大家很明顯就能看出,我就不做總結(jié)。我們最終選擇的方案是第一種,并且在驗證過程中增加了一個 Session識別子系統(tǒng),防止非法的阻塞和冒充。即在應(yīng)用子系統(tǒng)將用戶重定向到統(tǒng)一認(rèn)證系統(tǒng)系統(tǒng)時,子系統(tǒng)與用戶建立Session,并在用戶轉(zhuǎn)交認(rèn)證 信息時,驗證是否原本用戶。防止有非法者獲取了和用戶轉(zhuǎn)交的認(rèn)證信息,并在用戶之前提交給子系統(tǒng),騙取認(rèn)證。