微信小程序新舊數據庫權限對比

先說結論:新版規則如果妥善編輯安全規則與雲函數,完全能夠實現與舊版支持的所有安全規則。但是新版規則將權限劃分得更細,並可以自己定義規則,所以靈活性、管理能力上比舊版要強。

舊版權限能力及行爲

數據庫的權限分爲小程序端和管理端,管理端包括雲函數端和控制檯,我願稱之爲後臺。小程序端運行在小程序中,讀寫數據庫受權限控制限制;管理端運行在雲函數上,擁有所有讀寫數據庫的權限。雲控制檯的權限同管理端,擁有所有權限。小程序端操作數據庫應有嚴格的安全規則限制(需要調用微信小程序給出的接口,接口內封裝了安全規則)。
雲開發爲雲數據庫做了小程序深度整合,在小程序中創建的每個數據庫記錄都會帶有該記錄創建者(即小程序用戶)的信息,以 _openid 字段保存用戶的 openid 在每個相應用戶創建的記錄中。因此,權限控制也相應圍繞着一個用戶是否應該擁有權限操作其他用戶創建的數據展開。初期微信雲開發數據庫提供了四種基礎權限配置,適用於簡單的前端訪問控制,只支持 4 種預設的規則(對集合中的每條數據記錄):

  1. 所有用戶可讀,僅創建者可寫。比如文章。
  2. 僅創建者可讀寫。比如用私密相冊。
  3. 所有用戶可讀,只有後臺可以讀寫。如商品信息。
  4. 所有用戶不可讀寫。如後臺用的隨機數等祕密信息。

但基礎的設置給前端的訪問權限控制是有一定侷限性、同時會帶來一些容易疑惑的、需要深入理解的系統默認行爲,微信官方文檔給出以下內容:

  1. 訪問權限控制要求只能基於記錄的 _openid 字段和用戶的 openid,更新記錄時,不允許修改 _openid
  2. 當權限爲 “僅創建者可讀寫” 時,查詢時會默認給查詢條件加上一條 _openid 必須等於用戶 openid
  3. 當權限爲 “僅創建者可讀寫” 或 “所有用戶可讀,僅創建者可寫” 時,更新前會默認先帶上 _openid 必須等於用戶 openid 的查詢條件,再將查詢到的結果進行更新,即使是用 doc.update 也是如此(因此我們會見到即使我們沒有對應 _id 的記錄的訪問權限,但是更新操作不會失敗,只會在返回的結果中說明 updated 更新的記錄數量爲 0)。
  4. 創建記錄時,會自動給記錄加上 _openid 字段,值等於用戶 openid,並且不允許用戶在創建記錄時嘗試設置 _openid
    根據以上的描述,不難看出舊版的安全規則是完全基於openid的,所以對這條數據的管理增加了相當多的限制,如創建時默認生成、不允許用戶更改等。

新版規則與能力

在官方給出的新版規則模板中,已經實現了舊版的四項能力,不過額外需要在雲函數中插入_openid:{openid}的條件判斷。如:

{
  // 所有用戶可讀,僅創建者可寫
  "read": true,
  "write": "doc._openid == auth.openid"
}
{
  // 僅創建者可讀寫
  "read": "doc._openid == auth.openid",
  "write": "doc._openid == auth.openid"
}

新版規則對於想在雲端對數據進行增刪改查時,必須手動鍵入openid的判斷條件,因爲此時的openid將不再是必選的。而且舊版的安全規則是隻區分了“讀”和“寫”,並沒有進一步細分“寫”的內容。在新版安全規則下,微信將“寫”細分爲 create、update、delete。所以可以構造更加複雜的安全規則,如:

{
  // 自定義的對帖子的基本操作
  "read": "auth != null", // 所有登錄用戶可讀
  "create": "auth != null", // 所有登錄用戶可以發帖
  "update": "doc._openid == auth.openid", // 用戶只能修改自己的帖子
  "delete": "doc._openid == auth.openid" // 用戶只能刪除自己的帖子
}

上面的auth就是用戶的登錄信息,auth==null表示用戶還沒有登錄,而auth.openid就表示用戶的openid,doc.userID表示這條數據庫所有者的id。
升級由於openid不再是顯式傳入的,如doc一類基於id的操作往往是規則禁止的,爲了方便管理,微信官方建議換成where並顯式添加openid的判斷條件。帶來的兼容性問題官方也給出了相應的文檔說明:升級與兼容說明
綜合來看,微信小程序新版的安全功能粒度會更加細一些,可以自己定義對數據的操作能力。所以總體而言,對應的靈活度上升了。

權限測試

新舊版的規則差異,其實說穿了就是一點:舊版規則相對死板,但是對應的接口比較完整,wx內會默認完成當前openid是否有權限的判斷;新版規則相對靈活,爲了減少束縛可以自己調整接口,默認是不會進行openid的匹配的。例如如果在雲函數中不寫_openid:‘{openid}’的話,就會變成所有人可讀。
現在舉一個雲函數的例子如下:

// 雲函數入口文件
	const cloud = require('wx-server-sdk')
	cloud.init({
	  env:'xixotest1-1scbh'
	})
	const db=cloud.database().collection("huangqiangBook2")
	// 雲函數入口函數
	exports.main = async (event,context) => {
	  let { OPENID, APPID, UNIONID } = cloud.getWXContext()
	  return await db.where({
	    // _openid: OPENID,
	    // _id:"e6a3b07d5eeae2f2000a964b0dd3a761"
	  }).get()
	}

雲函數大致框架,修改部分就是where中註釋掉的兩行(上述代碼塊中13,14行)。
當權限規則設置是:

{
  "read": "doc._openid == auth.openid",
  "write": "doc._openid == auth.openid"
}

分別採用本地調用和雲函數調用。由於本地調用中默認會進行openid的比較,當數據庫中有若干條不滿足訪問條件的數據時,會發生“越權訪問”的報錯,從而導致一條數據也無法返回。當採用雲函數調用時,如果加上對應openid的判斷,由於雲函數中訪問數據時,如果出現越權訪問的情況,是不會拋出異常的,取而代之的是返回結果爲空。所以在雲函數中訪問時纔可以比較適配兼容這種“新規則”。總體來看雲函數具有更好的規則兼容性。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章