筋斗雲接口編程 / 對象型接口(四)

定製可訪問數據

除了限制用戶可以訪問哪些表和字段,還常會遇到一類需求是限制用戶只能訪問自己的數據。

[任務]

用戶登錄後,可以添加訂單、查看自己的訂單。
我們在設計文檔中設計接口如下:

添加訂單
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}", "不是你的訂單,不可操作");
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章