---
title: 允許和拒絕
slug: allow-and-deny
date: 0008/01/02
number: 8.5
points: 10
sidebar: true
contents: 研究允許(Allow)和拒絕(Deny)的回函調數.|理解回函調數的可執行性順序.
paragraphs: 16
---
Meteor 的安全系統不需要我們在每次修改數據的時候,在各自的函數里面進行手動檢查。
例如,對于一個博客系統,我們常常需要做很多操作,往新帖子上添加屬性,當發布帖子的時候進行特定檢查。這些操作都是圍繞帖子(post)這個對象進行的,所以我們應該為帖子設置一個專門的函數進行安全檢查。
但在另一方面,我們又不希望為修改帖子或刪除帖子這些簡單的操作編寫特定的函數。我們只需要在這些操作之前,檢查用戶是否有權限就可以了。這時我們就需要用到允許(allow)和拒絕(deny)回調函數。
這些回調函數可以方便地讓我們定義哪些數據可以被修改,哪些可以被刪除。另外,這些回調函數還整合了用戶系統(account system),用以判斷權限。
### 多個回調函數
我們可以根據需要定義多個允許 `allow` 回調函數。但是我們只需要其中_至少有一個_返回 `true` 就可以讓操作通過驗證。當 `Post.insert` 被調用時(無論是在我們 app 的客戶端代碼調用,還是在瀏覽器控制臺調用),服務器會逐個運行為 insert 設置的允許(allow)回調函數,直到其中一個返回 `true` 為止。如果這樣的允許回調函數不存在,服務器就不會允許 insert 操作,并給客戶端返回一個 `403` 錯誤。
類似地,我們也可以定義一個或者多個拒絕 `deny` 回調函數。如果其中一個回調函數返回 `true`,操作就會被取消,并且返回 `403`。這意味著,一個成功的 insert 操作要求至少一個返回 `true` 的允許 `allow` 回調函數,并且_所有_拒絕 `deny` 回調函數都返回 `false`。
<%= diagram "allow_deny", "注:n/e 表示該函數沒有被執行" %>
更直觀地說,Meteor 從拒絕回調函數開始,然后是 `allow` 函數,逐一執行,直到有一個返回 `true`。
這個模式的一個實際例子就是,建立兩個 `allow()` 允許回調函數,一個用于檢查帖子是否屬于當前用戶,另外一個用于檢查當前用戶是否管理員。如果當前用戶是管理員,由于至少有一個回調函數返回 `true`,那就確保他們可以更新任何帖子。
### 延遲補償
還記得我們前面說過,數據庫的可變函數(例如 `.update()`)使用了一種延遲補償技術。所以,當你嘗試從瀏覽器的控制臺刪除一篇不屬于你的帖子的時候,你會看到帖子短時間內消失,但馬上又會重新出現。這是因為帖子并沒有真正從后臺刪除,刪除操作被后臺拒絕了。
這樣的行為在控制臺上不是問題(開發者可以隨意支配數據進行開發)。但是,你需要確保這樣的行為不會出現在用戶界面上。比如說,你需要確保對于用戶不能刪除的帖子,用戶不會看到刪除鍵。
慶幸的是,你可以在客戶端和服務端使用一樣的代碼進行權限管理(例如,你可以寫一個 `canDeletePost(user, post)` 函數,把它放在一個共享的 `/lib` 文件夾下面),這樣做通常不需要太多額外的代碼。
### 服務端權限
只有來自客戶端的數據庫操作需要被權限系統驗證。服務端的_所有_操作都被認定為安全的,不需要被權限系統驗證。
這意味著如果你創建了一個服務端函數 `deletePost`,而且這個函數可以被客戶端執行,那么任何用戶都可以刪除任何帖子了。因此,你可能不想那么做,除非你在函數中也驗證用戶權限。