Sails 中的政策是功能強大的工具,用於授權和存取控制:它們讓您在執行動作之前先執行一些邏輯,以判斷是否繼續處理請求。政策最常見的用例是將某些動作限制為僅限已登入的使用者。
注意:政策僅適用於控制器和動作,不適用於視圖。如果您在您的 routes.js 設定檔 中定義了一個直接指向視圖的路徑,則不會對其應用任何政策。為了確保應用政策,您可以改為定義一個顯示視圖的動作,然後將您的路徑指向該動作。
最好避免在您的應用程式中實作大量或複雜的政策。相反地,當實作諸如精細、基於角色的權限等功能時,請依賴您的動作來拒絕不必要的存取。您的動作也應負責任何必要的視圖局部變數和您在回應中傳送的 JSON 回應資料的個人化設定。
例如,如果您需要在您的應用程式中實作使用者層級或基於角色的權限,最直接的解決方案是在您的控制器動作的頂部處理相關的檢查 — 可以直接內聯或呼叫輔助函式。遵循此最佳實務將顯著提高您程式碼的可維護性。
Sails 內建了一個 ACL(存取控制列表),位於 config/policies.js
中。此檔案用於將政策對應到動作和控制器。
此檔案是宣告式的,表示它描述了您的應用程式的權限應該看起來像什麼,而不是它們應該如何運作。這使得新開發人員更容易理解正在發生的事情,並且隨著需求的不可避免的變化,它使您的應用程式更加靈活。
config/policies.js
檔案是一個字典,其屬性和值取決於您是否將政策應用於控制器或獨立動作。
要將政策應用於控制器,請使用控制器名稱作為 config/policies.js
字典中的屬性名稱,並將其值設定為一個字典,該字典將該控制器中的動作對應到應應用於它們的政策。使用 *
來表示「所有未對應的動作」。政策的名稱與其檔案名稱相同,減去副檔名。
module.exports.policies = {
UserController: {
// By default, require requests to come from a logged-in user
// (runs the policy in api/policies/isLoggedIn.js)
'*': 'isLoggedIn',
// Only allow admin users to delete other users
// (runs the policy in api/policies/isAdmin.js)
'delete': 'isAdmin',
// Allow anyone to access the login action, even if they're not logged in.
'login': true
}
};
要將政策應用於一個或多個獨立動作,請使用動作路徑(相對於 api/controllers
)作為 config/policies.js
字典中的屬性名稱,並將該值設定為應應用於這些動作的政策。透過在動作路徑的末尾使用萬用字元 *
,您可以將政策應用於所有以該路徑開頭的動作。以下是與上述相同的政策集,經過重寫以應用於獨立動作
module.exports.policies = {
'user/*': 'isLoggedIn',
'user/delete': 'isAdmin',
'user/login': true
}
請注意,此範例與基於控制器的政策範例略有不同,因為
isLoggedIn
政策將適用於api/controllers/user
資料夾及其子資料夾中的所有動作(除了user/delete
和user/login
,這將在下一節中說明)。
重要的是要注意政策不會級聯。在上面的範例中,isLoggedIn
政策將應用於 UserController.js
檔案(或位於 api/controllers/user
下的獨立動作)中的所有動作,除了 delete
和 login
之外。如果您希望將多個政策應用於一個動作,請在陣列中列出這些政策。例如
'getEncryptedData': ['isLoggedIn', 'isInValidRegion']
Sails 的內建 藍圖 API 是使用常規的 Sails 動作實作的。唯一的區別是藍圖動作是隱含的。
要將您的政策應用於藍圖動作,請像我們在上面的範例中所做的那樣設定您的政策對應,但指向您控制器中相關的隱含 藍圖動作 的名稱(或作為獨立動作)。例如
module.exports.policies = {
UserController: {
// Apply the 'isLoggedIn' policy to the 'update' action of 'UserController'
update: 'isLoggedIn'
}
};
或
module.exports.policies = {
'user/update': 'isLoggedIn'
};
您可以使用 *
屬性將政策應用於所有未以其他方式明確對應的動作。例如
module.exports.policies = {
'*': 'isLoggedIn',
'user/login': true
};
這會將 isLoggedIn
政策應用於除 api/controllers/user/login.js
(或 api/controllers/UserController.js
中)的 login
動作之外的每個動作。
Sails 提供了兩個內建政策,可以全域應用或應用於特定的控制器或動作
true
:公開存取(允許任何人存取對應的控制器/動作)false
:禁止存取(允許任何人都無法存取對應的控制器/動作)
'*': true
是所有控制器和動作的預設政策。在生產環境中,最好將其設定為 false
,以防止存取您可能無意中暴露的任何邏輯。
這是一個簡單的 isLoggedIn
政策,用於防止未經驗證的使用者存取。它檢查會話中是否有 userId
屬性,如果找不到,則傳送預設的 forbidden
回應 值。
// policies/isLoggedIn.js
module.exports = async function (req, res, proceed) {
// If `req.me` is set, then we know that this request originated
// from a logged-in user. So we can safely proceed to the next policy--
// or, if this is the last policy, the relevant action.
// > For more about where `req.me` comes from, check out this app's
// > custom hook (`api/hooks/custom/index.js`).
if (req.me) {
return proceed();
}
//--•
// Otherwise, this request did not come from a logged-in user.
return res.forbidden();
};