權限控制
Univer 提供權限控制能力,用於限制使用者對工作簿、工作表、選區的操作。當使用者執行無權限動作時,Univer 會中止執行並提示缺失權限。常見場景如:對一片選區設定保護,限制協作者的編輯/檢視/複製等能力。
依任務跳轉到下方章節。本頁集中介紹基礎操作、進階範例、設定與疑難排解;完整 API 定義統一在 Reference 中維護。
核心概念
- 作用範圍:權限可以作用在工作簿、工作表、選區三個層級。
- 權限點位:每個功能對應一個權限點位,修改點位即可控制功能是否可用。
- 保護規則:工作表和選區在設定權限點位前,需要先建立保護規則。
本地非持久化權限可直接修改權限點位;持久化整合見 權限服務整合
協同編輯場景下,更新權限點位會同步更新服務端狀態:
- false:該權限點至少需要
owner角色 - true:該權限點至少需要
reader角色
基礎示例
使用 allowedUsers 範例前,請將 user1、user2 替換為權限服務已傳回的真實協作者 ID。
下面按工作簿、工作表、選區三個層級展示最常見的權限設定方式。
工作簿權限程式碼示例
工作簿層級權限透過 Facade API 直接修改權限點位即可。
以編輯權限為例(其他功能只需替換權限點位,參考權限點位列表 - 工作簿):
const fWorkbook = univerAPI.getActiveWorkbook()if (!fWorkbook) throw new Error('No active workbook')const workbookPermission = fWorkbook.getWorkbookPermission()// 設定工作簿不可編輯await workbookPermission.setPoint(univerAPI.Enum.WorkbookPermissionPoint.Edit, false)要點:
- 工作簿權限點位可以直接設定,不需要建立保護規則。
工作表權限程式碼示例
工作表和選區相關的權限設定可以透過 Facade API 或命令系統實現。這裡以工作表編輯權限舉例,其他功能只需替換權限點位,參考權限點位列表 - 工作表。
const fWorkbook = univerAPI.getActiveWorkbook()if (!fWorkbook) throw new Error('No active workbook')const fWorksheet = fWorkbook.getActiveSheet()const worksheetPermission = fWorksheet.getWorksheetPermission()// 建立工作表保護, 允許指定使用者編輯const permissionId = await worksheetPermission.protect({ allowedUsers: ['user1', 'user2'], name: 'My Worksheet Protection',})// 如果需要設定權限點位,必須先建立工作表保護await worksheetPermission.setPoint(univerAPI.Enum.WorksheetPermissionPoint.Edit, false)刪除工作表權限
const fWorkbook = univerAPI.getActiveWorkbook()if (!fWorkbook) throw new Error('No active workbook')const fWorksheet = fWorkbook.getActiveSheet()const worksheetPermission = fWorksheet.getWorksheetPermission()// 刪除工作表保護await worksheetPermission.unprotect()自訂選區權限程式碼示例
選區的權限同樣支援 API 和命令模式。這裡以選區編輯權限舉例,其他選區功能只需替換權限點位,參考權限點位列表 - 選區。
const fWorkbook = univerAPI.getActiveWorkbook()if (!fWorkbook) throw new Error('No active workbook')const fWorksheet = fWorkbook.getActiveSheet()const fRange = fWorksheet.getRange('A1:B2')const rangePermission = fRange.getRangePermission()// 設定區域保護權限,允許指定使用者編輯但不允許他人檢視const rule = await rangePermission.protect({ name: 'My protected range', allowViewByOthers: false, allowedUsers: ['user1', 'user2'],})console.log(rule)// 如果需要設定權限點位,必須先建立區域保護await rule.setPoint(univerAPI.Enum.RangePermissionPoint.Edit, false)await rule.setPoint(univerAPI.Enum.RangePermissionPoint.View, true)刪除區域保護權限
const fWorkbook = univerAPI.getActiveWorkbook()if (!fWorkbook) throw new Error('No active workbook')const fWorksheet = fWorkbook.getActiveSheet()const fRange = fWorksheet.getRange('A1:B2')const rangePermission = fRange.getRangePermission()// 刪除區域内所有保護規則await rangePermission.unprotect()// 或刪除區域内指定規則const rules = await rangePermission.listRules()if (rules.length > 0) { await rules[0].remove()}常用任務
將活頁簿設為唯讀
const fWorkbook = univerAPI.getActiveWorkbook()if (!fWorkbook) throw new Error('No active workbook')const permission = fWorkbook.getWorkbookPermission()await permission.setMode('viewer')console.log(permission.getSnapshot())管理保護範圍
const fWorkbook = univerAPI.getActiveWorkbook()if (!fWorkbook) throw new Error('No active workbook')const fWorksheet = fWorkbook.getActiveSheet()const permission = fWorksheet.getWorksheetPermission()const createdRules = await permission.protectRanges([ { ranges: [fWorksheet.getRange('A1:B2')], options: { name: 'Public area', allowViewByOthers: true }, }, { ranges: [fWorksheet.getRange('C3:D4')], options: { name: 'Private area', allowViewByOthers: false, allowedUsers: ['user1'] }, },])console.log(createdRules)const rules = await permission.listRangeProtectionRules()const firstRule = rules[0]if (firstRule) { await firstRule.updateRanges([fWorksheet.getRange('A1:B3')])}排查儲存格權限
const fWorkbook = univerAPI.getActiveWorkbook()if (!fWorkbook) throw new Error('No active workbook')const permission = fWorkbook.getActiveSheet().getWorksheetPermission()console.log(permission.debugCellPermission(0, 0))權限點位列表
不同的功能權限由不同的權限點位控制,修改點位的值即可控制對應功能。具體點位程式碼請參閱這裡。
如果 workbook 的權限控制和 worksheet / range 有交叉,那麼必須全部為 true 才能使用。例如一個單元格的編輯權限必須 workbook 和 worksheet 的編輯權限都為 true 才能編輯。
工作簿
| API 列舉 | 對應權限點位類 | 描述 |
|---|---|---|
| univerAPI.Enum.WorkbookPermissionPoint.Edit | WorkbookEditablePermission | 能否編輯 |
| univerAPI.Enum.WorkbookPermissionPoint.View | WorkbookViewPermission | 能否檢視 |
| univerAPI.Enum.WorkbookPermissionPoint.Print | WorkbookPrintPermission | 能否列印 |
| univerAPI.Enum.WorkbookPermissionPoint.Export | WorkbookExportPermission | 能否匯出 |
| univerAPI.Enum.WorkbookPermissionPoint.Share | WorkbookSharePermission | 能否分享 |
| univerAPI.Enum.WorkbookPermissionPoint.CopyContent | WorkbookCopyPermission | 能否複製 |
| univerAPI.Enum.WorkbookPermissionPoint.DuplicateFile | WorkbookDuplicatePermission | 能否複製文件 |
| univerAPI.Enum.WorkbookPermissionPoint.Comment | WorkbookCommentPermission | 能否評論 |
| univerAPI.Enum.WorkbookPermissionPoint.ManageCollaborator | WorkbookManageCollaboratorPermission | 能否管理協作者 |
| univerAPI.Enum.WorkbookPermissionPoint.CreateSheet | WorkbookCreateSheetPermission | 能否建立工作表 |
| univerAPI.Enum.WorkbookPermissionPoint.DeleteSheet | WorkbookDeleteSheetPermission | 能否刪除工作表 |
| univerAPI.Enum.WorkbookPermissionPoint.RenameSheet | WorkbookRenameSheetPermission | 能否重新命名工作表 |
| univerAPI.Enum.WorkbookPermissionPoint.MoveSheet | WorkbookMoveSheetPermission | 能否移動工作表 |
| univerAPI.Enum.WorkbookPermissionPoint.HideSheet | WorkbookHideSheetPermission | 能否隱藏工作表 |
| univerAPI.Enum.WorkbookPermissionPoint.CopySheet | WorkbookCopySheetPermission | 能否複製工作表 |
| univerAPI.Enum.WorkbookPermissionPoint.ViewHistory | WorkbookViewHistoryPermission | 能否檢視歷史記錄 |
| univerAPI.Enum.WorkbookPermissionPoint.RecoverHistory | WorkbookRecoverHistoryPermission | 能否恢復歷史記錄 |
| univerAPI.Enum.WorkbookPermissionPoint.CreateProtection | WorkbookCreateProtectPermission | 能否建立保護 |
| univerAPI.Enum.WorkbookPermissionPoint.InsertRow | WorkbookInsertRowPermission | 能否插入行 |
| univerAPI.Enum.WorkbookPermissionPoint.InsertColumn | WorkbookInsertColumnPermission | 能否插入列 |
| univerAPI.Enum.WorkbookPermissionPoint.DeleteRow | WorkbookDeleteRowPermission | 能否刪除行 |
| univerAPI.Enum.WorkbookPermissionPoint.DeleteColumn | WorkbookDeleteColumnPermission | 能否刪除列 |
工作表
| API 列舉 | 對應權限點位類 | 描述 |
|---|---|---|
| univerAPI.Enum.WorksheetPermissionPoint.Edit | WorksheetEditPermission | 能否編輯 |
| univerAPI.Enum.WorksheetPermissionPoint.View | WorksheetViewPermission | 能否檢視 |
| univerAPI.Enum.WorksheetPermissionPoint.Copy | WorksheetCopyPermission | 能否複製 |
| univerAPI.Enum.WorksheetPermissionPoint.SetCellValue | WorksheetSetCellValuePermission | 能否編輯單元格值 |
| univerAPI.Enum.WorksheetPermissionPoint.SetCellStyle | WorksheetSetCellStylePermission | 能否編輯單元格樣式 |
| univerAPI.Enum.WorksheetPermissionPoint.SetRowStyle | WorksheetSetRowStylePermission | 能否設定行樣式 |
| univerAPI.Enum.WorksheetPermissionPoint.SetColumnStyle | WorksheetSetColumnStylePermission | 能否設定列樣式 |
| univerAPI.Enum.WorksheetPermissionPoint.InsertRow | WorksheetInsertRowPermission | 能否插入行 |
| univerAPI.Enum.WorksheetPermissionPoint.InsertColumn | WorksheetInsertColumnPermission | 能否插入列 |
| univerAPI.Enum.WorksheetPermissionPoint.DeleteRow | WorksheetDeleteRowPermission | 能否刪除行 |
| univerAPI.Enum.WorksheetPermissionPoint.DeleteColumn | WorksheetDeleteColumnPermission | 能否刪除列 |
| univerAPI.Enum.WorksheetPermissionPoint.Sort | WorksheetSortPermission | 能否排序 |
| univerAPI.Enum.WorksheetPermissionPoint.Filter | WorksheetFilterPermission | 能否篩選 |
| univerAPI.Enum.WorksheetPermissionPoint.PivotTable | WorksheetPivotTablePermission | 能否使用透視表 |
| univerAPI.Enum.WorksheetPermissionPoint.InsertHyperlink | WorksheetInsertHyperlinkPermission | 能否使用超連結 |
| univerAPI.Enum.WorksheetPermissionPoint.ManageCollaborator | WorksheetManageCollaboratorPermission | 能否管理協作者 |
| univerAPI.Enum.WorksheetPermissionPoint.DeleteProtection | WorksheetDeleteProtectionPermission | 能否刪除保護 |
| univerAPI.Enum.WorksheetPermissionPoint.EditExtraObject | WorksheetEditExtraObjectPermission | 能否編輯額外物件 |
| univerAPI.Enum.WorksheetPermissionPoint.SelectProtectedCells | WorksheetSelectProtectedCellsPermission | 能否選取受保護儲存格 |
| univerAPI.Enum.WorksheetPermissionPoint.SelectUnProtectedCells | WorksheetSelectUnProtectedCellsPermission | 能否選取未受保護儲存格 |
區域保護
| API 列舉 | 對應權限點位類 | 描述 |
|---|---|---|
| univerAPI.Enum.RangePermissionPoint.Edit | RangeProtectionPermissionEditPoint | 能否編輯保護區域 |
| univerAPI.Enum.RangePermissionPoint.View | RangeProtectionPermissionViewPoint | 能否檢視保護區域的內容 |
| univerAPI.Enum.RangePermissionPoint.Delete | RangeProtectionPermissionDeleteProtectionPoint | 能否刪除保護區域 |
| univerAPI.Enum.RangePermissionPoint.ManageCollaborator | RangeProtectionPermissionManageCollaPoint | 能否管理保護區域的協作者 |
權限介面設定
權限保護範圍陰影策略
若要區分目前使用者可編輯和不可編輯的保護區域,請使用 non-editable:可編輯的保護區域不顯示陰影,編輯權限遭停用的保護區域保留陰影;不可檢視的保護範圍仍保留遮罩。
此設定控制範圍保護和工作表保護的顯示,不會建立保護規則或修改編輯、檢視權限,也不會在未受保護的區域新增陰影。請先依上文設定保護規則和目前使用者的權限。
| 策略 | 顯示效果 |
|---|---|
true / 'always' | 顯示所有保護區域的陰影(預設)。 |
'non-editable' | 隱藏可編輯保護區域的陰影,保留不可編輯區域的陰影。 |
'non-viewable' | 僅顯示不可檢視保護區域的陰影。 |
false / 'none' | 隱藏全部保護陰影,權限檢查仍然生效。 |
權限陰影示意
切換策略,比較同一組區域對目前使用者的顯示效果。
未保護
無陰影
已保護 · 可編輯
無陰影
已保護 · 唯讀
顯示陰影
已保護 · 不可檢視
顯示陰影
此示意只改變陰影,不改變權限。即使選擇 none,不可檢視的內容也不會顯示。
初始化時設定:
univer.registerPlugin(UniverSheetsUIPlugin, { protectedRangeShadow: 'non-editable',})createUniver({ presets: [ UniverSheetsCorePreset({ sheets: { protectedRangeShadow: 'non-editable', }, }), ],})也可以透過 API 動態修改:
下方 Facade API 會更新目前 Univer 執行個體中既有活頁簿的顯示策略。外掛模式下需先匯入 @univerjs/sheets-ui/facade;Sheets Core 預設已包含此匯入。
// 設定只顯示不可編輯範圍的陰影univerAPI.setProtectedRangeShadowStrategy('non-editable')// 獲取當前的權限保護範圍陰影顯示策略console.log(univerAPI.getProtectedRangeShadowStrategy())// 監聽權限保護範圍陰影顯示策略的變化const subscription = univerAPI.getProtectedRangeShadowStrategy$().subscribe((strategy) => { console.log('Global strategy changed to:', strategy) // 更新 UI 或執行其他操作})// 稍後,取消訂閱以進行清理subscription.unsubscribe()自訂使用者元件
Univer 內建的自訂使用者元件所適配的場景比較有限,如果需要更復雜的自訂元件,可以透過以下方式進行自訂。
可在《自訂元件》檢視如何自訂元件。
univer.registerPlugin(UniverSheetsUIPlugin, { protectedRangeUserSelector: { /** * custom component, should implement the `IPermissionDetailUserPartProps` interface. */ component: CustomPermissionDetailUserPart, /** * The framework of the component. Must be passed correctly. */ framework: 'react', },})const { univer } = createUniver({ presets: [ UniverSheetsCorePreset({ sheets: { protectedRangeUserSelector: { /** * custom component, should implement the `IPermissionDetailUserPartProps` interface. */ component: CustomPermissionDetailUserPart, /** * The framework of the component. Must be passed correctly. */ framework: 'react', }, }, }), ],})在使用者選擇器的變更回呼中呼叫 setSelectUserList()。以下最小 React 範例清空已選使用者:useDependency 在元件內呼叫,服務狀態只在點擊後更新。完整選擇器請依 IPermissionDetailUserPartProps 實作。
import type { IPermissionDetailUserPartProps } from '@univerjs/sheets-ui'import type { FC } from 'react'import { SheetPermissionUserManagerService } from '@univerjs/sheets-ui'import { useDependency } from '@univerjs/ui'export const CustomPermissionDetailUserPart: FC<IPermissionDetailUserPartProps> = () => { const service = useDependency(SheetPermissionUserManagerService) const clearSelection = () => service.setSelectUserList([]) return <button type="button" onClick={clearSelection}>清空已選使用者</button>}import type { IPermissionDetailUserPartProps } from '@univerjs/preset-sheets-core'import type { FC } from 'react'import { SheetPermissionUserManagerService, useDependency } from '@univerjs/preset-sheets-core'export const CustomPermissionDetailUserPart: FC<IPermissionDetailUserPartProps> = () => { const service = useDependency(SheetPermissionUserManagerService) const clearSelection = () => service.setSelectUserList([]) return <button type="button" onClick={clearSelection}>清空已選使用者</button>}去除權限彈窗
univerAPI.setPermissionDialogVisible(false)權限服務整合
拓展使用
當你需要在自己的外掛中增加權限校驗時,可以直接操作權限點位。
下面以 WorkbookEditablePermission 為例,其他點位類似:
import { IPermissionService } from '@univerjs/core'import { WorkbookEditablePermission } from '@univerjs/sheets'class YourService { constructor(@IPermissionService private _permissionService: IPermissionService) { } setWorkbookNotEditable() { this._permissionService.updatePermissionPoint(new WorkbookEditablePermission('unitId').id, false) } setWorkbookEditable() { this._permissionService.updatePermissionPoint(new WorkbookEditablePermission('unitId').id, true) }}第三方外掛如何擴充權限點位
如果你需要自訂權限點位,可以實現 IPermissionPoint 並註冊到權限服務中:
import type { IPermissionPoint } from '@univerjs/core'import { IPermissionService, PermissionStatus } from '@univerjs/core'import { UnitAction, UnitObject } from '@univerjs/protocol'export class CustomPermissionPoint implements IPermissionPoint { type = UnitObject.Unkonwn // your type subType = UnitAction.View // your subType status = PermissionStatus.INIT value = true // 權限的初始值 id: string constructor(unitId: string, subUnitId: string, customId: string) { // 這裡自行拼湊一個 id,id 屬性需要保證在整個 IPermissionService 中是唯一的憑證。 this.id = `${unitId}.${subUnitId}.${customId}` }}class YourService { constructor(@IPermissionService private _permissionService: IPermissionService) { this._init() } _init() { this._permissionService.addPermissionPoint(new CustomPermissionPoint('unitId', 'subUnitId', 'my-id')) }}// 在其他地方如何使用class ConsumeService { constructor(@IPermissionService private _permissionService: IPermissionService) { } doSomething() { const point = this._permissionService.getPermissionPoint(new CustomPermissionPoint('unitId', 'subUnitId', 'my-id').id) console.log(point?.value) } bindEvent() { // 這將獲得一個 Rx 物件,使得你能夠監聽當前權限的變化作出一些改變 const point$ = this._permissionService.getPermissionPoint$(new CustomPermissionPoint('unitId', 'subUnitId', 'my-id').id) console.log(point$) }}第三方權限服務接入(進階用法)
在業務應用中實作 IAuthzIoService,將權限、角色與協作者方法接入後端。以下範例假定 ./authorization-service 已將該實作匯出為 YourAuthzService。請在建立活頁簿前註冊,並保留其他初始化選項與外掛註冊。
import { IAuthzIoService, Univer } from '@univerjs/core'import { YourAuthzService } from './authorization-service'const univer = new Univer({ override: [[IAuthzIoService, { useClass: YourAuthzService }]],})服務需要持久化保護規則與協作者變更,傳回目前使用者的權限,並傳遞請求失敗。傳回空清單的 mock 不具備持久化能力。協同情境下,後端仍須分別驗證讀取、JOIN 與修改權限,見身分與權限。前端保護與隱藏陰影不能取代伺服器授權。
協作者管理
協作者管理由業務應用程式和權限服務負責。請接入自己的使用者與 ACL 模型,在伺服器端分別檢查讀取、JOIN 和修改權限,見身分與權限。下方前端 API 需要匹配的權限服務實作,不會自動設定伺服器端權限。
- 獲取協作者列表
const fWorkbook = univerAPI.getActiveWorkbook()if (!fWorkbook) throw new Error('No active workbook')const workbookPermission = fWorkbook.getWorkbookPermission()const collaborators = await workbookPermission.listCollaborators()console.log(collaborators)- 新增協作者
const fWorkbook = univerAPI.getActiveWorkbook()if (!fWorkbook) throw new Error('No active workbook')const workbookPermission = fWorkbook.getWorkbookPermission()// 一次新增多個協作者await workbookPermission.setCollaborators([ { user: { userID: 'user1', name: 'John Doe', avatar: 'https://...' }, role: univerAPI.Enum.UnitRole.Editor, }, { user: { userID: 'user2', name: 'Jane Smith', avatar: '' }, role: univerAPI.Enum.UnitRole.Reader, },])// 新增單個協作者await workbookPermission.addCollaborator( { userID: 'user1', name: 'John Doe', avatar: 'https://...' }, univerAPI.Enum.UnitRole.Editor,)- 更新協作者角色
const fWorkbook = univerAPI.getActiveWorkbook()if (!fWorkbook) throw new Error('No active workbook')const workbookPermission = fWorkbook.getWorkbookPermission()await workbookPermission.updateCollaborator( { userID: 'user1', name: 'John Doe Updated', avatar: 'https://...' }, univerAPI.Enum.UnitRole.Reader,)- 刪除協作者
const fWorkbook = univerAPI.getActiveWorkbook()if (!fWorkbook) throw new Error('No active workbook')const workbookPermission = fWorkbook.getWorkbookPermission()// 刪除多個協作者await workbookPermission.removeCollaborators(['user1', 'user2'])// 刪除單個協作者await workbookPermission.removeCollaborator('user1')Reference
你覺得這篇文檔如何?