定製可訪問數據
除了限制用戶可以訪問哪些表和字段,還常會遇到一類需求是限制用戶只能訪問自己的數據。
[任務]
用戶登錄後,可以添加訂單、查看自己的訂單。
我們在設計文檔中設計接口如下:
添加訂單
Ordr.add()(amount) -> id
查看訂單
Ordr.query() -> tbl(id, userId, status, amount)
Ordr.get(id) -> { 同query接口字段...}
應用邏輯
- 權限:AUTH_USER
- 用戶只能添加(add)、查看(get/query)訂單,不可修改(set)、刪除(del)訂單
- 用戶只能查看(get/query)屬於自己的訂單。
- 用戶在添加訂單時,必須設置amount字段,不可設置userId, status這些字段。
後端將userId字段自動設置爲該用戶編號,status字段自動設置爲"CR"(已創建)
上面接口原型描述中,get接口用”…”省略了詳細的返回字段,因爲返回對象的字段與query接口是一樣的,兩者寫清楚一個即可。
實現對象型接口,我們一般寫到文件php/api_objects.php中:
class AC1_Ordr extends AccessControl
{
protected $allowedAc = ["get", "query", "add"];
protected $requiredFields = ["amount"];
protected $readonlyFields = ["status", "userId"];
// get/query接口會回調
protected function onQuery()
{
$userId = $_SESSION["uid"];
$this->addCond("t0.userId={$userId}");
}
// add/set接口會回調
protected function onValidate()
{
if ($this->ac == "add") {
$userId = $_SESSION["uid"];
$_POST["userId"] = $userId;
$_POST["status"] = "CR";
}
}
}
在get/query操作中,會回調
onQuery
函數,在這裏我們用addCond
添加了一條限制:用戶只能查看到自己的訂單。
addCond
的參數可理解爲SQL語句中WHERE子句的片段;字段用”t0.userId”來表示,其中”t0”表示當前操作表”Ordr”的別名(alias)。後面會講到聯合查詢(join)其它表,就可能使用其它表的別名。add/set操作會回調
onValidate
函數(本例中$allowedAc
中未定義”set”,因而不會有”set”操作過來)。在這個回調中常常設置$_POST[字段名]
來自動完成一些字段。注意
$_SESSION["uid"]
變量是在用戶登錄成功後設置的,由於”AC1”類是用戶登錄後使用的,所以必能取到該變量。
[任務]
我們把需求稍擴展一下,現在允許set/del操作,即用戶可以更改和刪除自己的訂單。
可以這樣實現:
class AC1_Ordr extends AccessControl
{
protected $allowedAc = ["get", "query", "add", "set", "del"];
...
// get/set/del接口會回調
protected function onValidateId()
{
$uid = $_SESSION["uid"];
$id = mparam("id");
$rv = queryOne("SELECT id FROM Ordr WHERE id={$id} AND userId={$uid}");
if ($rv === false)
throw new MyException(E_FORBIDDEN, "not your order");
}
}
可通過onValidateId
回調來限制get/set/del操作時,只允許訪問自己的訂單。
函數mparam
用來取必傳參數(m表示mandatory)。
函數queryOne
用來查詢首行數據,如果查詢只有一列,則返回首行首列數據,但如果查詢不到數據,就返回false.
這裏如果返回false,既可能是訂單id不存在,也可能是雖然存在但是是別人的訂單,簡單處理,我們都返回一個E_FORBIDDEN異常。
框架對異常會自動處理,一般不用特別再檢查數據庫操作失敗之類的異常。如果返回錯誤對象,可拋出MyException
異常:
throw new MyException(E_FORBIDDEN);
錯誤碼”E_FORBIDDEN”表示沒有權限,不允許操作;常用的其它錯誤碼還有”E_PARAM”,表示參數錯誤。
MyException的第二個參數是內部調試信息,第三個參數是對用戶友好的報錯信息,比如:
throw new MyException(E_FORBIDDEN, "order id {$id} does not belong to user {$uid}", "不是你的訂單,不可操作");