從 Salesforce (SFDC) 拉資料就偶而會被 Field-Level Security (FLS) 打到,而 FLS 那藏地有夠緊的設定頁面、加上從台灣連到美東那精美的連線速度,每每要敲個幾個欄位下來都很有得等...
找到了以程式來直接設定 FLS 的手段,這樣就不用去戳那個有夠煩的 UI 了,記錄一下。
環境設定
以下操作是 SOQL 及 Metadata API 混用;然後實際上我是使用 simple-salesforce 來操作,不過在 workbench 混用 SOQL Query 及 REST Explorer 也能完成。
使用 simple-salesforce 連線的程式大概這樣起頭,其中 Salesforce 的建構子參數都做授權在用,直接看官方文件比較快:
import simple_salesforce
client = simple_salesforce.Salesforce( ... )
列舉欄位清單
先打個 sObject Describe 當作測試:
client.Account.describe()
但取得清單卻意外地沒用——作為管理員帳號明明已經可以在 Object Management 上看到所有的欄位了、甚至在上面調整權限,但是當 FLS 沒有通過,欄位就不會在 API 的回應裡出現。即從這個 API 取得的完整欄位清單會跟實際上有出入。
取得 PermissionSet
稍後查詢需要得到 PermissionSet 的資訊,先打個 SOQL 去查查:
SELECT id
FROM PermissionSet
WHERE
    IsOwnedByProfile = true
    AND PermissionSet.Profile.Name = 'System Administrator'
這裡 PermissionSet.Profile.Name 顧名思義是需要取得權限的帳號的群組名,例如上面的 System Administrator 或是自訂的群組如 Service Account。
如果也是使用 simple-salesforce 的話就直接透過 query 來執行:
client.query( soql )
確認權限
FLS 背後的物件為 FieldPermissions,一樣透過 SOQL 來查查權限:
SELECT
    SobjectType,
    Field,
    ParentId,
    PermissionsRead,
    PermissionsEdit
FROM FieldPermissions
WHERE
    Field = 'Account.Website'
這裡舉例是以標準物件 Account 下的內建欄位 Website 來檢索並回傳了 FieldPermissions 的全部欄位:
| 回傳欄位 | 說明 | 
|---|---|
| SobjectType | 所屬 SObject 名稱 | 
| Field | 欄位的 API 識別名稱,並且它一定要以其所屬 SObject 名稱作為前綴 | 
| ParentId | 這個 FieldPermissions物件所對應的PermissionSet | 
| PermissionsRead | 具有可讀權限 | 
| PermissionsEdit | 具有可寫權限 | 
另外,不是所有的欄位都可以查詢 FieldPermissions,以 FieldPermissions 文件底下 Special Properties for Field Permissions 章節所述,一些系統欄位會是永遠唯獨的,包括但不僅於:
- Id
- CreatedById
- CreatedDate
- IsDeleted
- LastModifiedById
- LastModifiedDate
- SystemModStamp
這些系統欄位無法查詢、也不可以對那些欄位設定 FieldPermissions。對於系統欄位,在 sObject Describe 回傳的欄位資料中 permissionable 會是 False。
開權限
SOQL 只能查資料,所以這塊是 Metadata API 的戰場。這裡要操作的是對 FieldPermissions 打 Create Records:
POST /services/data/v58.0/sobjects/FieldPermissions/{
    "SobjectType": "Account",
    "Field": "Account.Website",
    "PermissionsEdit": false,
    "PermissionsRead": true,
    "ParentId": "0xxxxxxxxxxxxxxMUD"
}
依照前面段落說到的規則:Field 一樣需要把  SObject 填在前面,然後 ParentId 就直接填入要開權限的對象。
在 simple-salesforce 中的操作則對應為:
client.FieldPermissions.create({
    "SobjectType": "Account",
    "Field": "Account.Website",
    "PermissionsEdit": False,
    "PermissionsRead": True,
    "ParentId": "0xxxxxxxxxxxxxxMUD"
})
 
    