协作批注权限
InkLayer 的协作权限用于控制批注器中的写操作:谁可以创建批注、回复评论,以及谁可以移动、缩放、编辑、修改状态或删除已有内容。React 和 Vue 使用相同的权限模型,只有组件绑定语法不同。
InkLayer 不负责登录或身份认证。
user必须来自你的应用,权限判断依赖稳定且可信的user.id,不需要额外传入role。
快速开始
React
import { PdfAnnotator } from 'inklayer-react'
import type { AnnotationPermissions, User } from 'inklayer-react'
const currentUser: User = { id: 'alice', name: 'Alice' }
const permissions: AnnotationPermissions = {
mode: 'owner-only',
can: ({ currentUser }) =>
currentUser?.id === 'admin' ? true : undefined,
}
export function ReviewDocument() {
return (
<PdfAnnotator
url="/document.pdf"
user={currentUser}
annotationPermissions={permissions}
defaultShowAnnotationAuthorLabels
layoutStyle={{ height: '100vh' }}
/>
)
}
Vue
<script setup lang="ts">
import { PdfAnnotator } from 'inklayer-vue'
import type { AnnotationPermissions, User } from 'inklayer-vue'
const currentUser: User = { id: 'alice', name: 'Alice' }
const permissions: AnnotationPermissions = {
mode: 'owner-only',
can: ({ currentUser }) =>
currentUser?.id === 'admin' ? true : undefined,
}
</script>
<template>
<PdfAnnotator
url="/document.pdf"
:user="currentUser"
:annotation-permissions="permissions"
default-show-annotation-author-labels
:layout-style="{ height: '100vh' }"
/>
</template>
当前用户与作者归属
user 表示当前正在操作批注器的业务用户:
interface User {
id: string
name: string
}
id用于权限判断,必须在用户切换、刷新和重新加载文档后保持稳定。name用于界面展示,可以变化,不应作为权限依据。id为空或等于默认值'null'时,owner-only会把当前用户视为未认证用户,所有写操作都会被拒绝。- 切换
user后,后续操作会立即按照新的当前用户重新判断。
显示批注作者标签
defaultShowAnnotationAuthorLabels 决定批注器初始化时是否显示全部批注的作者标签,React 和 Vue 的默认值均为 false:
<PdfAnnotator defaultShowAnnotationAuthorLabels />
<PdfAnnotator default-show-annotation-author-labels />
false只是不默认展开全部标签;选中某条批注时,仍会显示该批注的作者。- 用户可以通过批注工具栏中的作者标签按钮持续显示或隐藏全部标签。
- 在 macOS 按住
Command,或在 Windows/Linux 按住Alt,可以临时显示全部作者标签,松开后恢复原状态。 - 该 Prop 只设置初始化状态,不是用于持续控制显示状态的受控开关。
- 作者标签来自批注中保存的作者显示信息。它只帮助识别内容归属,不会改变
annotationPermissions的判断结果;权限仍以稳定的作者 ID 和当前user.id为准。
权限模式
annotationPermissions.mode 支持两种模式:
| 模式 | 默认行为 |
|---|---|
unrestricted | 默认值。保持兼容行为,所有批注和回复写操作均允许。 |
owner-only | 有效用户可以创建批注和回复;只有内容作者可以管理自己的内容。 |
如果未传入 annotationPermissions,等同于:
{ mode: 'unrestricted' }
owner-only 操作矩阵
| 操作 | 批注作者 | 其他有效用户 | 无有效用户 |
|---|---|---|---|
| 创建批注 | 允许 | 允许 | 拒绝 |
| 回复批注 | 允许 | 允许 | 拒绝 |
| 移动或缩放批注 | 允许 | 拒绝 | 拒绝 |
| 编辑批注 | 允许 | 拒绝 | 拒绝 |
| 修改批注状态 | 允许 | 拒绝 | 拒绝 |
| 删除批注 | 允许 | 拒绝 | 拒绝 |
| 编辑或删除回复 | 仅回复作者允许 | 拒绝 | 拒绝 |
权限系统只限制写操作。用户仍然可以查看、选择和阅读自己无权修改的批注。
使用 can(request) 覆盖默认规则
can 是可选的同步函数。InkLayer 会先根据 mode 计算 defaultAllowed,再调用 can:
interface AnnotationPermissions {
mode?: 'unrestricted' | 'owner-only'
can?: (request: AnnotationPermissionRequest) => boolean | undefined
}
返回值含义:
| 返回值 | 结果 |
|---|---|
true | 强制允许当前操作 |
false | 强制拒绝当前操作 |
undefined | 保留 mode 计算出的 defaultAllowed |
request 包含:
| 字段 | 说明 |
|---|---|
action | 当前请求的写操作 |
currentUser | 当前用户;不可用时可能为 null |
annotation | 当前批注;创建操作时可能不存在 |
comment | 当前回复;非回复操作时可能不存在 |
defaultAllowed | 当前 mode 已经计算出的默认结果 |
支持的操作
type AnnotationPermissionAction =
| 'annotation.create'
| 'annotation.transform'
| 'annotation.edit'
| 'annotation.delete'
| 'annotation.comment'
| 'annotation.change-status'
| 'comment.edit'
| 'comment.delete'
管理员覆盖
const permissions: AnnotationPermissions = {
mode: 'owner-only',
can: ({ currentUser }) =>
currentUser?.id === 'admin' ? true : undefined,
}
管理员返回 true,其他用户返回 undefined,继续使用 owner-only 的归属规则。
整个批注器只读
React:
<PdfAnnotator annotationPermissions={{ can: () => false }} />
Vue:
<PdfAnnotator :annotation-permissions="{ can: () => false }" />
只读模式下仍可选择和查看批注,但所有写操作都会被禁止。
禁止删除
const permissions: AnnotationPermissions = {
mode: 'owner-only',
can: ({ action }) =>
action === 'annotation.delete' ? false : undefined,
}
文档锁定后禁止修改
const permissions: AnnotationPermissions = {
mode: 'owner-only',
can: ({ currentUser }) => {
if (documentLocked) return false
if (currentUser?.id === 'admin') return true
return undefined
},
}
这里的 documentLocked 来自应用自己的文档或审批状态。上面的顺序表示文档锁定后管理员也不能修改;如果管理员应该绕过锁定规则,可以先判断管理员。
can必须同步返回。请提前加载用户角色、文档状态和审批信息,再通过闭包传入;不要返回Promise。如果权限函数抛出异常,InkLayer 会拒绝当前操作,避免意外放行。
保存与恢复作者信息
owner-only 依赖持久化数据中的作者 ID。保存和重新加载批注时,不要删除或改写:
- 批注的
meta.authorId - 回复的
user
meta.authorId 可以是字符串 ID,也可以是用户对象:
annotation.meta.authorId = {
id: 'alice',
name: 'Alice',
}
如果旧数据没有作者信息,InkLayer 无法确认当前用户是拥有者,这些批注在 owner-only 下不能被编辑。迁移旧数据时,应使用业务系统中真实且稳定的用户 ID 补齐作者归属。
前端权限不是安全边界
annotationPermissions 控制 InkLayer 界面和浏览器中的本地写操作,但不能替代服务端授权。
后端仍必须验证:
- 当前会话是否有权访问文档
- 保存或删除的批注是否属于当前用户
- 管理员或审批权限是否真实有效
- 客户端提交的
authorId是否允许写入
不要直接信任客户端传来的权限结果、用户 ID 或批注作者信息。
常见问题
开启 owner-only 后所有按钮都不可用
确认传入的 user.id 非空且不等于 'null'。
当前用户无法编辑重新加载的旧批注
确认保存的数据保留了 annotation.meta.authorId,并且它与当前 user.id 完全一致。
管理员覆盖没有生效
确认 can 返回的是布尔值 true,并且管理员 ID 与 currentUser.id 一致。返回 undefined 会继续使用模式默认结果。
可以在 can 中请求后端吗?
不可以。can 是同步判断。应先获取业务权限,再生成或更新 annotationPermissions。