SiYuan v3.6.0 文档级发布访问控制详解从界面操作到源码实现【免费下载链接】siyuanAn open-source, privacy-first, self-hosted knowledge workspace where humans and AI agents work together 开源、隐私优先、自托管的知识工作空间让人与智能体在此协作项目地址: https://gitcode.com/GitHub_Trending/si/siyuanv3.6.0 是 SiYuan 笔记发布能力的一次重要升级从这一版本开始发布服务不再只是全库可见或全库不可见的二元开关而是可以在文档树面板中为单个文档单独设置访问级别。本文以 v3.6.0 变更记录 为核心结合仓库源码与语言包完整讲解五种发布访问级别的含义、操作路径、数据存储格式、密码认证机制以及隐藏在kernel/model/publish_access.go中的过滤实现原理帮助你在自托管发布场景下精确控制每一个文档的公开范围。一、功能概述从整库发布到文档级访问控制在 v3.6.0 之前SiYuan 的发布服务粒度是库级别的启用发布服务后通过设置中的 Basic 认证见 kernel/conf/publish.go 中的Publish配置结构统一决定整个工作空间是否对外可见。这种模式要么全开、要么全关无法满足公开部分内容、隐藏部分内容的真实需求。v3.6.0 引入的文档级访问控制对应 PR #16041改变了这一局面官方变更说明只有一句话我们现在可以为发布服务设置文档级访问权限了文档树面板 - 更多 - 发布访问控制。这条简单的说明背后是一套贯穿前端 UI、HTTP API、配置文件与发布渲染过滤链路的完整机制。下面我们从用户操作开始逐层深入。二、五种访问级别语义、图标与配置映射访问级别由三个底层字段组合决定前端将这些组合抽象为五种级别其定义位于前端 app/src/protyle/util/publishAccess.ts级别图标说明语言包原文VisiblePasswordDisable公开public完全公开访问true空false保护protected公众可见需密码访问true非空false隐藏hidden公众不可见可直接访问false空false私密private公众不可见需密码访问false非空false禁止forbidden禁止访问false空true五种级别的文案来源于语言包 app/appearance/langs/zh-CN.json其中公开文档及其资源对所有人可见等同于默认状态也不会被写入访问控制配置保护文档列表、搜索等场景可见但打开文档正文时需要输入密码隐藏公众不可见但已经拿到链接或路径的用户可以直接访问不要求密码私密公众不可见且需要密码才能访问禁止文档在发布内容中彻底不可见、不可访问属于最高级别的封锁。后端对应的数据结构定义在 kernel/model/publish_access.go三个 JSON 字段visible、password、disable与上表完全对应type PublishAccessItem struct { ID string json:id Visible bool json:visible // 是否发布可见 Password string json:password // 密码为空字符串时表示无密码 Disable bool json:disable // 是否禁止发布 }注意protected与private的区别仅在于visible字段前者文档对外可见如文档树、搜索结果中出现后者在导航类输出中被隐藏两者都需要密码才能读取正文。三、界面操作在文档树面板中设置访问级别3.1 打开设置入口操作路径为文档树面板 → 文档更多菜单 → 发布访问控制。在 app/src/layout/dock/Files.ts 中可以看到该菜单项的注册与交互逻辑菜单项使用语言包键publishAccess中文显示为发布访问控制点击后调用openPublishAccessDialog打开级别选择弹窗并通过/api/filetree/getPublishAccess接口ids参数传入当前文档 ID回填该文档当前的访问级别与已设密码。3.2 选择访问级别并设置密码弹窗 UI 由 app/src/protyle/util/publishAccess.ts 中的openPublishAccessDialog渲染界面包含一排图标按钮分别对应 公开、 保护、 隐藏、 私密、 禁止五个级别一个动态显示当前级别的说明文字来自publishAccess*Comment语言键一个密码输入框——仅在保护和私密级别下显示前端根据hasPassword标志切换显示/隐藏。选择级别并输入密码后点击确认前端会将文档 ID 与{visible, password, disable}组合通过/api/filetree/setPublishAccess提交给内核。3.3 服务端保存逻辑接口实现在 kernel/api/filetree.go 的setPublishAccess函数中其行为值得注意对已存在的记录执行更新若更新结果为公开visible password 为空 !disable则直接从配置中删除该条目避免配置冗余对不存在的记录仅在非公开即设置了保护/隐藏/私密/禁止时才新增条目更新后调用model.PurgePublishAccess()清理无效条目见 kernel/model/publish_access.go该函数会检查所有笔记本均已打开后才移除已不存在的文档 ID 对应记录避免误删关闭笔记本中的状态。四、持久化publishAccess.json 存储格式访问控制配置保存在工作空间数据目录下的data/.siyuan/publishAccess.json中。读写逻辑见 kernel/model/publish_access.goGetPublishAccess()首次读取后带30 秒内存缓存publishAccessLastModified时间戳30 秒内的重复读取直接返回缓存降低磁盘 IO文件不存在时会自动创建并写入[]SetPublishAccess()通过filelock.WriteFile原子写入避免并发读写损坏配置。一个典型配置示例两个文档一个保护、一个禁止[ { id: 20230405172236-pg3l9eu, visible: true, password: mypassword, disable: false }, { id: 20230429115711-ejbts4s, visible: false, password: , disable: true } ]该文件属于工作空间数据会随数据目录一起备份/同步无需手工编辑——所有修改都应通过界面完成手工编辑需保证 JSON 合法且 ID 为真实存在的文档 ID。五、密码机制继承规则与 Cookie 认证5.1 路径向上查找的密码继承密码不是只看当前文档的简单逻辑。GetPathPasswordByPublishAccesskernel/model/publish_access.go实现了沿文档路径向上逐级查找的规则从当前文档路径开始逐级向父级目录查找命中任一设置了密码的祖先文档即返回该密码若整条文档路径都没有密码最后检查笔记本本身box即笔记本 ID是否设置了密码。这意味着给某个父文档设置保护其全部子文档在发布时都会被同一密码保护父文档密码可覆盖子文档设置形成树状继承的密码体系。5.2 认证 Cookie用户输入正确密码后服务端通过SetPublishAuthCookiekernel/model/publish_access.go写入名为publish-auth-{文档ID}的 Cookie值为SHA256(ID password)哈希不存储明文密码MaxAge为 24 小时标记为HttpOnly前端脚本无法读取降低 XSS 窃取风险若服务启用了 SSLCookie 附加Secure标志。校验函数CheckPublishAuthCookie会重新计算哈希并与 Cookie 比对任何未通过校验的请求在渲染层都会被锁挡住。六、渲染与过滤发布时如何拦截受限内容访问控制真正的落地在发布服务的每一处内容输出路径上全部集中在 kernel/model/publish_access.go 中。核心原则是发布时过滤而非发布前删除——受限文档的数据仍然在库中只是在对外输出时被拦截或替换。主要过滤函数包括过滤函数作用范围FilterContentByPublishAccessL470文档正文内容受密码保护时渲染 密码输入框被禁止时渲染 禁止提示FilterBlocksByPublishAccess/FilterPathsByPublishAccess块查询、文档树/路径列表按visible与密码可见性过滤FilterViewByPublishAccessL290数据库/属性视图表格、画廊、看板按首列文档块逐行过滤并替换受限文档的封面FilterBlockInfoByPublishAccess文档信息清空受限文档的 name/alias/memo/bookmark/tags 等 IAL避免元数据泄露FilterGraphByPublishIgnore/FilterTagsByPublishIgnore关系图谱节点与链接、标签计数剔除被禁止文档FilterCriteriaByPublishAccess搜索历史/条件丢弃引用不可访问文档的条目并清空K/R关键字防止通过搜索泄露路径FilterRecentDocsByPublishAccess最近文档列表FilterAssetContentByPublishAccess/CheckAbsPathAccessableByPublishAccess资源文件assets访问仅当资源属于某个可访问文档时才放行其中正文渲染的拦截 HTML 见FilterContentByPublishAccess密码锁与禁止提示会以protyle-password类名的 DOM 注入到内容流中同时在 kernel/api/filetree.go 中文档内容拉取接口/api/filetree/getDoc在只读角色上下文下会先经过该过滤器并把scroll置为false避免长页面通过滚动反复刷出多个锁。对于属性视图FilterViewByPublishAccess会递归处理分组Groups并依据默认第一个属性是文档块的约定定位每行/每卡对应的文档树节点被禁止的文档行/卡直接置空剔除看板视图还会同步修正CardCount。从源码结构看这套过滤机制已被广泛接入发布服务的各类数据出口kernel/api/block.go、kernel/api/search.go、kernel/api/graph.go、kernel/api/tag.go 等多个 API 文件均调用了model.GetPublishAccess()并套用上述过滤器可以推断其设计目标是让任何可能暴露受限内容的查询路径都被同一套策略收敛尽量减少遗漏面。七、v3.6.0 其他值得关注的变更除文档级发布访问控制外v3.6.0 变更记录 还包含以下改进同样值得升级后体验7.1 编辑器体验改进代码块中的粘贴体验#14647优化了向代码块粘贴内容时的格式处理支持将文档标题设置为空#17110此前文档标题不可置空现在允许将文档标题清空便于以正文首行或其他方式组织内容改进文档末尾按↓键的交互#17116光标位于文档末尾时按方向键的行为更符合直觉改进子级菜单的显示#17172修复子菜单定位与层级展示问题。7.2 移动端与数据库初始化移动端插件侧边栏时清空容器内容#16271避免侧边栏在重复初始化时残留旧内容支持在浏览器中将文件通过拖放上传到数据库资源字段单元格#16817Web 端数据库的资源类型字段现在支持拖拽文件直接上传与桌面端体验对齐。7.3 安全与工程修复forwardProxy接口的 SSRF 漏洞#17175这是一个安全修复项涉及forwardProxy接口的服务器端请求伪造风险建议所有自托管用户尽快升级升级至 Electron v40.8.1#17185桌面端运行时升级带来上游安全修复与性能改进使用 CSS 类管理窗口状态样式#16811窗口状态如聚焦/失焦的样式控制从逐条样式设置改为 CSS 类管理属于面向主题开发者的工程化重构也降低了插件/主题对窗口状态做自定义的成本。八、升级与使用建议升级路径从 v3.6.0 之前的版本升级后data/.siyuan/publishAccess.json会在首次设置访问级别时自动创建无需迁移数据若未做过任何设置该文件保持[]发布行为与旧版一致。发布前自检配置完访问控制后建议以无痕窗口打开发布地址分别验证五种级别文档的可见性、密码输入与 Cookie 24 小时有效期、以及受限文档关联的资源图片是否被正确拦截。密码规划充分利用沿路径向上继承的特性——为整个目录设置一个父级密码即可统一保护其下所有子文档不必逐个设置。注意配置位置访问控制配置属于工作空间数据跟随数据目录存储更换设备或迁移工作空间后需要确认该文件随数据一同迁移否则发布访问控制会丢失。参考与延伸阅读变更记录原文v3.6.0 变更记录后端核心实现kernel/model/publish_access.go设置/查询接口kernel/api/filetree.go前端级别映射与弹窗app/src/protyle/util/publishAccess.ts文档树菜单入口app/src/layout/dock/Files.ts语言包文案app/appearance/langs/zh-CN.json发布服务基础配置启用开关、端口 6808、Basic 认证kernel/conf/publish.go【免费下载链接】siyuanAn open-source, privacy-first, self-hosted knowledge workspace where humans and AI agents work together 开源、隐私优先、自托管的知识工作空间让人与智能体在此协作项目地址: https://gitcode.com/GitHub_Trending/si/siyuan创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考