就我們的目的而言,工作階段 定義為允許您在請求之間儲存使用者代理程式資訊的幾個組件。
使用者代理程式 是代表您在裝置上的軟體(瀏覽器或原生應用程式),例如電腦上的瀏覽器分頁、智慧型手機應用程式或冰箱。它與 Cookie 或存取權杖一對一關聯。
工作階段可能非常有用,因為請求/回應週期是無狀態的。請求/回應週期被認為是無狀態的,因為用戶端和伺服器本身都不會在不同請求之間儲存關於特定請求的任何資訊。因此,請求/回應的生命週期在對請求的使用者代理程式做出回應時結束(例如 res.send()
)。
注意:我們將在瀏覽器使用者代理程式的上下文中討論工作階段。雖然您可以在 Sails 中將工作階段用於任何您喜歡的用途,但通常最佳實務是僅將其用於儲存使用者代理程式身份驗證的狀態。身份驗證是一個允許使用者代理程式證明他們具有特定身份的過程。例如,為了存取某些受保護的功能,我可能需要證明我的瀏覽器分頁實際上對應於資料庫中的特定使用者記錄。如果我向您提供唯一的名稱和密碼,您可以查找該名稱並將我的密碼與儲存的(希望是加密的)密碼進行比較。如果匹配,我就通過身份驗證。但是,您如何在請求之間儲存這種「已驗證」的狀態呢?這就是工作階段的用武之地。
Sails 中工作階段的實作有三個主要組件
sails.sid
)工作階段儲存區可以是記憶體(這是預設的 Sails 工作階段儲存區)或資料庫(Sails 內建支援使用 Redis 來達到此目的)。Sails 建構於 Connect middleware 之上來管理工作階段,其中包括使用 Cookie 在使用者代理程式上儲存工作階段 ID(sid
)。
當請求傳送到 Sails 時,請求標頭會由工作階段中介軟體解析。
如果標頭不包含 Cookie,則會在工作階段中建立一個 sid
,並且預設的工作階段字典會新增到 req
(例如 req.session
)。此時,您可以變更工作階段屬性(通常在控制器/動作中)。例如,讓我們看看以下登入動作
module.exports = {
login: function(req, res) {
// Authentication code here
// If successfully authenticated
req.session.userId = foundUser.id; // returned from a database
return res.json(foundUser);
}
}
在這裡,我們將 userId
屬性新增到 req.session
。
注意: 該屬性不會儲存在工作階段儲存區中,也不會在回應傳送之前提供給其他請求。
一旦回應傳送,任何新的請求都將可以存取 req.session.userId
。由於我們的請求標頭中沒有 Cookie,因此將為我們建立一個 Cookie。
Sails.sid
的 Cookie現在,當使用者代理程式發出下一個請求時,將檢查 Cookie 上儲存的 Sails.sid
的真實性。如果它與工作階段儲存區中現有的 sid
相符,則工作階段儲存區的內容將作為屬性新增到 req
字典(req.session
)。我們可以存取 req.session
上的屬性(例如 req.session.userId
)或在其上設定屬性(例如 req.session.userId == someValue
)。工作階段儲存區中的值可能會變更,但 Sails.sid
和 sid
通常不會變更。
Sails.sid
何時會變更?在開發期間,Sails 工作階段儲存區位於記憶體中。因此,當您關閉 Sails 伺服器時,目前的工作階段儲存區會消失。當 Sails 重新啟動時,即使使用者代理程式請求在 Cookie 中包含 Sails.sid
,sid
也不再位於工作階段儲存區中。因此,將產生一個新的 sid
並在 Cookie 中替換。如果使用者代理程式 Cookie 過期或被移除,Sails.sid
也會變更。
Sails Cookie 的生命週期可以從其預設設定(永不過期)變更為新設定,方法是存取
projectName/config/session.js
中的cookie.maxAge
屬性。
Redis 是一個鍵值資料庫套件,可以用作與 Sails 執行個體分離的工作階段儲存區。此工作階段設定有兩個好處。第一個是工作階段儲存區將在 Sails 重新啟動之間保持可用。第二個是,如果您在負載平衡器後方有多個 Sails 執行個體,則所有執行個體都可以指向單一整合的工作階段儲存區。
若要在開發中啟用 Redis 作為您的工作階段儲存區,請先確保您的機器上已執行本機 Redis 執行個體 (redis-server
)。然後,使用 sails lift --redis
啟動您的應用程式。
這只是 sails lift --session.adapter=@sailshq/connect-redis --sockets.adapter=@sailshq/socket.io-redis
的快捷方式。這些套件預設包含為新 Sails 應用程式的依賴項,但如果您正在使用升級後的應用程式,則需要 npm install @sailshq/connect-redis
和 npm install @sailshq/socket.io-redis
。
請注意,此內建設定使用您的本機 Redis 執行個體。如需進階工作階段設定選項,請參閱 Reference > Configuration > sails.config.session。
Cookie 的值是透過首先使用可設定的密鑰(只是一個長字串)對 sid
進行雜湊處理來建立的。
您可以在
projectName/config/session.js
中變更工作階段secret
屬性。
然後,Sails sid
(例如 Sails.sid
)會變成純 sid
,後跟 sid
加上 secret
的雜湊值的組合。為了將其從抽象世界中取出,讓我們使用一個範例。Sails 建立一個 sid
為 234lj232hg234jluy32UUYUHH
和一個 session secret
為 9238cca11a83d473e10981c49c4f
。這些值只是 Sails 組合和雜湊以建立 signature
為 AuSosBAbL9t3Ev44EofZtIpiMuV7fB2oi
的兩個字串。因此,Sails.sid
變成 234lj232hg234jluy32UUYUHH.AuSosBAbL9t3Ev44EofZtIpiMuV7fB2oi
,並透過在回應標頭中傳送 set-cookie
屬性儲存在使用者代理程式 Cookie 中。
這可以防止什麼? 這可以防止使用者猜測 sid
。它還可以防止惡意使用者欺騙使用者發出帶有惡意使用者知道的 sid
的身份驗證請求。這可能允許惡意使用者在使用工作階段進行身份驗證時使用 sid
來做壞事。
即使您的 Sails 應用程式設計為由非瀏覽器用戶端(例如烤麵包機)存取,也強烈建議您使用工作階段進行身份驗證。雖然有時理解起來可能很複雜,但 Sails 中的內建工作階段機制(工作階段儲存區 + HTTP 唯讀 Cookie)是一種經過考驗且真實可靠的解決方案,通常比自行推出某些東西更不易崩潰、更易於使用且風險更低。
也就是說,工作階段可能並不總是可選的(例如,如果您必須與不同的身份驗證方案(如 JWT)整合)。在這些情況下,您可以應用程式範圍或按請求停用工作階段。
若要完全關閉應用程式的工作階段支援,請將以下內容新增到您的 .sailsrc
檔案
"hooks": {
"session": false
}
這會停用核心 Sails 工作階段鉤子。您也可以透過將 sails_hooks__session
環境變數設定為 false
來完成此操作。
若要按路由(或按請求)關閉工作階段支援,請使用sails.config.session.isSessionDisabled
設定。預設情況下,Sails 會為所有請求啟用工作階段支援,除了那些看起來像指向靜態資源(如影像、樣式表等)的請求。