企业协同

Odoo 企业版 Documents 分享链接为什么不是“有个 URL 就都能看”:token、文件夹权限与上传边界讲透

很多人把 Odoo Documents 的外链分享理解成“生成一个 access URL”。但从 documents_document.py 和分享模板看,真正决定外部人能看什么、能不能上传、能否继续深入子文件夹的,是 token、user_permission、access_via_link、父文件夹权限和 owner 规则叠加出来的一套边界。本文把这套机制拆开讲清。

企业 协同办公
进阶 开发者 2 分钟阅读
0 评论 0 点赞 0 收藏 7 阅读

先说结论

Odoo 企业版 Documents 的“分享链接”绝不是“生成一个 URL 发出去”这么简单。

/home/ubuntu/odoo-temp/enterprise/documents/models/documents_document.pyviews/documents_templates_share.xml 看,真正决定访问边界的至少有 5 层:

  • document_token / access_token
  • access_url
  • 当前文档本身的 user_permission
  • access_via_link 是否开放查看或编辑
  • 父文件夹是否可达,以及模板是否据此暴露上传/下载入口

所以外部人能否访问,不是一个“有链 / 没链”的问题,而是:

这个 token 能把人带到哪里;到了那里以后,系统还认不认他对当前文档或父文件夹有权。


第一层:access URL 只是入口,不是最终授权结果

源码里 _compute_access_token() 会把 document_token 和记录 id 组合成一个 access_token,然后 _compute_access_url() 再生成类似:

  • /odoo/documents/<access_token>

这说明分享链接本质上只是一个可定位入口

它解决的是:

  • 用户不用先进入内部 web client 再找文档
  • 系统能够凭 token 找到目标文档或文件夹

但它并没有承诺“有链接就一定有权限”。

这一点从分享页模板的兜底提示也能看出来:

This document does not exist or is not publicly available.

也就是说,链接只负责“把请求导到正确对象”,真正是否可读,还要继续过权限判断。


第二层:Documents 的权限不是单点判断,而是来源叠加

_compute_user_permission() 这一段是整篇文章的核心。

它先调用 _get_permission_without_token_multi() 计算“不考虑 token 时,当前用户本来拥有什么权限”,然后再叠加 link-based access 等特殊情况。

权限来源大致有几层:

1. 系统管理员 / Documents 管理组

如果用户属于 documents.group_documents_system,并且公司上下文允许,权限几乎直接给到 edit

2. 文档 owner

如果文档 owner_id == 当前用户,默认能编辑。

3. 明确配置的 documents.access

代码会按 (document_id, partner_id) 找有效 access 记录,并结合 expiration date 判断是否仍生效。

如果文档本身不给权限,系统还会看:

  • 当前文档是否开放 access_via_link
  • 父文件夹是否可访问
  • 当前对象是不是 shortcut
  • link access 是否被隐藏

所以一个用户能看到文档,不一定是因为他“拥有这份文档”,也可能是因为:

  • 他是 owner
  • 他被单独授权了
  • 他能通过父文件夹进入
  • 他拿着一个具备 link-access 语义的入口

第三层:为什么“有分享链接却还是打不开”

源码里有一段非常关键的边界:

  • 如果 document.user_permission == 'none'
  • 但它有 folder_id
  • access_via_link != 'none'
  • 且 link access 没被隐藏
  • 且用户对父文件夹仍可达

那么系统才可能把当前文档权限提升到 document.access_via_link

这几乎等于在说:

链接权限不是凭空生效,而是模拟“你能顺着界面路径走到这里”的一层宽松入口。

并且注释里还专门写了:

  • 这只按“上一层父文件夹”来模拟
  • 不是无限级穿透

所以典型失败场景是:

  • 你发的是子文件或子文件夹链接
  • 但父级访问关系不成立
  • 系统就不会把 link access 无条件放大

这正是很多人误会的地方:Documents 的外链不是对象级万能通行证,它更像是受上下文约束的外部门把手


第四层:为什么有的分享页能上传,有的只能下载

documents_templates_share.xml,分享页是否显示 Upload 按钮,条件写得非常直白:

  • folder.access_via_link == 'edit'
  • folder.user_permission == 'edit'

也就是说,上传能力只在两种情况下开放:

  1. 这个分享的文件夹本身允许 link-based edit
  2. 当前访问者对这个文件夹本来就有 edit 权限

否则即使能打开分享页,也可能只有 Download All 或只读浏览。

这很好地解释了现场一个很常见的误解:

客户已经能看到共享文件夹了,为什么还是不能回传文件?

因为“能看”与“能上传”是两档权限,不是同一个开关。


第五层:为什么子文件夹和文件的行为看起来不完全一致

分享模板里对子文件夹、二进制文件、URL 文档做了不同渲染:

  • 子文件夹用自己的 access_token 跳转
  • binary 文档会看有没有 attachment / thumbnail / download 能力
  • requested document 在可编辑时会显示上传入口

这说明 Documents 的分享不是单一对象页面,而是一个按对象类型和当前权限动态降级的公共入口

同样是“一个分享文件夹里面的内容”,不同项可能出现:

  • 能下载
  • 能预览
  • 只能看名字
  • 需要补传文件
  • 能继续下钻到子文件夹

所以用户眼中的“不一致”,其实是模板把底层权限差异直接显露出来了。


第六层:root owner 与 share user 的限制,为什么很重要

_check_root_documents_owner_id() 会拦一类看似很细、其实很关键的错误:

  • root documents / folders 不能随便给 share user 当 owner

源码通过 _get_unauthorized_root_document_owners_sudo() 去筛掉这类 owner。

这背后的设计边界很明确:

  • 外部共享用户可以作为访问参与者
  • 但不应天然成为整棵根级文档树的所有者

这能避免 Documents 的“共享”演变成“外部人拥有内部根目录”的权限污染。


第七层:实施时最容易踩的 4 个坑

1. 把 token 当授权本身

错。token 更像定位入口,不是万能授权。

2. 忽略父文件夹可达性

如果你的分享模型依赖 folder 继承,那父级不可达时,子项 link access 也可能失效。

3. 误以为 view = upload

分享页能看,并不等于能上传;上传要求 edit

4. 把外部共享当内部协作

Documents 很适合做受控外链协作,但它不是“随便给链接就和内部同权”的设计。


最后一句

Odoo 企业版 Documents 的分享边界,真正值得理解的是这条顺序:

  • 先凭 token 找到对象
  • 再根据 owner / access record / folder / link rule 算 permission
  • 最后由分享模板决定给用户露出哪些动作

所以外链分享从来不是“一个链接搞定权限”,而是:

链接负责到达,权限负责可见,模板负责暴露动作。

把这三层分开看,Documents 的行为就不再神秘。

DISCUSSION

评论区

想参与讨论?先 登录 再发表评论。
还没有评论,你可以成为第一个留言的人。