[技術分享]跨應用Session 共用

狀況說明:

這次的專案是兩台以上的IIS機器要作負載平衡(NLB)

所以專案的IIS架構是兩台以上的機器要共用Session,而且有SSO的部分,在網路上分享的相關資訊上,web config有四種的sessionState狀態,可以決定Session的存放機制(請參考MSDN),我們打算是用SQLServer(把Session存到SQL Server)去存放Session,專案大致架構如下

A機器:放4個站台,彼此要作SSO機制,共用Session(跨站台、可遠端存取)
B機器:與A機器作負載平衡,需要判斷登入狀態時會去A機器取得Session

解釋完畢,接著是我整理網路上的資料,轉換成比較容易理解的:

ㄧ、觀念:
Session是搭配Cookie的一種技術,Cookie是在Client端建立一個文件用來暫存ㄧ些資料或是網頁的工作狀態,但因為ㄧ些敏感資料存在Client端會有安全性問題,因此才衍伸出Session的技術(把敏感資料或狀態儲存在Server)Client端的Cookie改成存一個很難破解規則的SessionID字串,透過SessionID可以去Sever端叫出各個Session值。重點:
1.不同的應用程式(Web App)預設不會共用Session,即使在同網域下,不同的AppName就不能共用,必須在作手動調整
2.
同台電腦不同Browser不會共用Session(但同Browser不同分頁可以共用)
3.Session的存放有4種模式(Web.config設定):
InProc(預設):Session存放在應用程式的執行緒內(存放在 Web 伺服器的記憶體中),只要更動到應用程式就一定會釋放(遺失),無法作Session共用等等的功能
StateServer: Session存放在應用程式的執行緒外(另外獨立出一個執行緒),不會隨著應用程式變更或重啟遺失,可以作Session共用,但不確定因素多(容易發生不預期的錯誤),要跨機器存取的話需要在特別去登入檔設定,否則預設是無法跨機器存取Session
SQLServer: 儲存在 SQL Server 資料庫中,相較前兩者,更加安全可靠,也比較好掌握。但需搭配內建存放Session專用的資料庫,但會稍微影響SQL Server的效能
Custom:使用者自訂,可搭配自行設計的資料表或是其他自訂的存放方法
4.Session共用的話MachineKey必需要一致,才能使得加密解密都是共同的Key

二、實作步驟:
1.      x64: 進入C:\WINDOWS\Microsoft.NET\Framework64\v4.0.30319 將此路徑複製
x86: 進入C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319 將此路徑複製
2.      CMD輸入: cd (剛剛的路徑)
接著輸入 aspnet_regsql.exe –S . -E -ssadd -sstype p
(如果SQL server不在本機請輸入: aspnet_regsql.exe -S 資料庫主機IP -U sa -P 密碼 -ssadd -sstype c -d 資料庫名稱)(這邊寫法很多,請參考:保哥的文章)

3.      修改每個要共用的WebApp的Web.config設定:<system.web>下加上<sessionState mode="SQLServer" sqlConnectionString="data source=(SQLServer的IP);initial catalog=SessionStateDB;user id=(登入ID);password=(登入密碼)" allowCustomSqlDatabase="true" timeout="(自行設定SessionTimeOut時間,單位分鐘)"/>
4.      IIS裡面設定好站台,點選[電腦金鑰]

把[在執行階段產生]&[每個應用程式產生唯一金鑰]取消勾選,再執行[產生金鑰]、最後[套用]。(圖片的金鑰僅供參考,請保護好金鑰避免外洩,造成資安問題)

接著到Web.config裡面,把剛剛IIS產生出來的整串金鑰連同<SessionState>的內容,複製貼上到其他要共用的WebApp

5.      SQL Server裡可以看到工具產生的DB,修改裡面的預存程序dbo.TempGetAppID,把set @appName=LOWER('ShareSession')  --把所有的APPName都設定成一樣名稱

三、補充資料表說明:
1.在透過微軟提供的工具建立好SessionDB後會自動在SQL Server的排程管理(SQL Agent)加入定時清除TimeOutSession,但Express版的沒有這功能,所以Session要自己手動清除(可以透過Windows排程定期執行,只是比較麻煩,需先建立個.bat.cmd檔去執行sqlcmd)
2.總共有兩個Table,介紹如下:
ASPStateTempSessions
欄位名稱
Type
說明
SessionId
nvarchar(88)
Session ID + application ID
Created
datetime
Date and time session was created (UTC)
Expires
datetime
Date and time session expires (UTC)
LockDate
datetime
UTC date and time session was locked
LockDateLocal
datetime
Local date and time session was locked
LockCookie
int
Lock ID
Timeout
int
Session timeout in minutes
Locked
bit
1=Session locked, 0=Session not locked
SessionItemShort
varbinary(7000)
Serialized session state (if <= 7,000 bytes)
SessionItemLong
image
Serialized session state (if > 7,000 bytes)
Flags
int
Session state flags (1=Uninitialized session)
ASPStateTempApplications
欄位名稱
Type
說明
AppId
int
Application ID
AppName
char(280)
Application name

3.當程式建立Session後系統會去把Sessionvm序列化,並依照序列化後的結果去呼叫不同的預存程序Insert Session,當序列化後的字串長度小於等於7000時會去執行[TempInsertStateItemShort]Session會存在欄位[SessionItemShort],大於7000則會執行[TempInsertStateItemLong]Session會存在欄位[SessionItemLong]

4.所有的預存程序都可更改,EX:當相同USER登入時要清掉先前的,可以先在TempInsertStateItemShort(TempInsertStateItemLong)裡修改成先清掉相同值的資料再新增


以上~希望自己下次能更進步,加油!!

留言