去年底我们接到了华东某设计院的定制化需求他们有300多名设计师日常处理大量CAD图纸和BIM模型核心诉求只有一个——“谁能看什么谁不能看什么必须管得死死的”。这不是个案。工程设计、机械制造、建筑设计这类行业图纸外泄是真正的命门。一张流出去的配方图纸可能价值数千万的研发投入。当时他们用的某国外品牌云盘权限模型是读/写/删三件套配上部门可见/不可见两个维度。产品经理听完需求就摇头说改不了底层逻辑。我们接手后用巴别鸟的权限体系重新设计三周上线至今稳定运行半年。这篇文章我就把32维度权限体系的技术实现细节讲清楚包括数据结构设计思路、权限校验的完整流程以及在设计院场景里真正落地的关键细节。一、为什么需要32个维度传统的文件权限模型RBAC基于角色的访问控制已经够用了吗够但不够细。举几个实际场景场景1图纸分区管理同一份结构图纸项目经理可以预览下载结构设计师只能预览不能下载外部协作的施工单位只能看特定版本监理单位只能看标注版本。这四套权限完全不同且随时可能变化。场景2单次外发管控图纸需要发给甲方但必须限制只能看7天、不能截图、不能转发、二次传播可追溯。这不是给不给权限的问题是给了权限之后还能管住的问题。场景3部门项目双重维度研发部的人不一定能看研发部的所有文件还需要看自己在某个项目里的权限。项目结束权限自动回收。传统RBAC做不了这个。于是我们设计了32个权限维度分成四层权限维度层级结构 ├── 身份层Who │ ├── 用户ID │ ├── 部门ID │ ├── 项目ID │ └── 角色Owner/Admin/Member/Viewer │ ├── 行为层What │ ├── 预览 │ ├── 下载 │ ├── 上传 │ ├── 删除 │ ├── 重命名 │ ├── 移动/复制 │ └── 外发 │ ├── 管控层How │ ├── 有效期开始时间结束时间 │ ├── 设备限制仅公司设备/仅指定设备 │ ├── IP限制仅内网/仅指定IP段 │ ├── 次数限制最多查看N次 │ ├── 水印策略强制水印/可选水印 │ └── 截屏管控允许/禁止/警告 │ └── 追踪层Trace ├── 操作日志谁、什么时间、什么操作 ├── 外发追踪是否被二次传播 └── 权限变更记录权限被谁改过32个维度不是32个开关是可以自由组合的权限元语。不同场景叠加不同维度才能实现精准到每一个操作行为的控制粒度。二、数据结构设计权限数据用什么结构存我们踩过坑最早用关系型数据库的ACL列表做出来后一测并发一高就撑不住——每次访问文件要查几十甚至上百条记录。现在我们用的是权限矩阵 继承 覆盖的三层模型。第一层权限矩阵Permission Matrix核心表结构CREATETABLEpermission_matrix(idBIGINTPRIMARYKEY,resource_idVARCHAR(64),-- 资源ID文件夹/文件subject_typeENUM(user,dept,project,role),subject_idVARCHAR(64),-- 主体IDpermission_set JSON,-- 权限集合 {preview:1, download:0, ...}inherit_fromVARCHAR(64),-- 继承自哪个文件夹override_flagTINYINT,-- 是否显式覆盖父级权限created_atTIMESTAMP,updated_atTIMESTAMP,INDEXidx_resource(resource_id),INDEXidx_subject(subject_type,subject_id));关键设计permission_set是JSON类型存的是这个主体对这个资源的具体权限组合。为什么用JSON而不是拆成32个字段因为权限维度会扩展用JSON灵活加减字段不用改表结构。第二层继承机制文件夹有层级权限也需要继承。子文件夹默认继承父文件夹的权限除非显式覆盖。-- 继承查询的伪代码functionresolvePermission(userId,fileId): fileChaingetFileAncestors(fileId)-- 从根目录到当前文件的路径effectivePermission{}forfolderinreversed(fileChain):-- 从近到远覆盖directPermqueryPermissionMatrix(userId,folder.id)ifdirectPerm.exists:ifdirectPerm.override_flag1: effectivePermissiondirectPerm.permission_setbreak-- 找到覆盖权限停止向上继承else:merge(effectivePermission,directPerm.permission_set)-- 最后加上文件自身的直接权限fileDirectqueryPermissionMatrix(userId,fileId)iffileDirect.exists:merge(effectivePermission,fileDirect.permission_set)returneffectivePermission第三层缓存层每次访问文件都走这个链路数据库扛不住。我们在Redis里做了两级缓存请求 → Redis本地缓存LRUTTL 30s→ Redis分布式缓存TTL 5min→ 数据库本地缓存用进程内LRU分布式缓存用于多节点同步失效。实测峰值QPS从数据库的2000提升到了5万。三、权限校验流程用户发起一个操作请求后权限校验是怎么走的以下载图纸为例用户点击下载 ↓ 前置校验登录状态、Token有效性 ↓ 获取用户属性UserID, DeptID, ProjectIDs[] ↓ 权限解析走上面的三层模型得到effectivePermission ↓ 行为校验preview1? download1? ↓ 管控层校验 ├── 时间窗口当前时间在有效期内 ├── 设备限制当前设备在白名单内 ├── IP限制当前IP在允许范围内 └── 次数限制已访问次数 限制 ↓ 记录操作日志Async非阻塞 ↓ 生成下载凭证带时效签名的临时URL ↓ 返回文件流有一个关键点管控层校验失败不等于拒绝访问而是限制性访问。比如设备不在白名单里可以降级为预览禁止下载而不是直接弹403。这个逻辑在设计院场景里特别有用——设计师临时用自己的笔记本查图纸总不能直接拒绝给他个预览权限等他回公司再用公司设备下载。四、设计院场景的关键实现这个项目里最有挑战的需求是外发文件管控。他们要把图纸发给施工单位但不能直接给原文件。我们实现了安全外发包机制外发包生成将图纸打包成受保护格式嵌入水印包含接收方信息、设置有效期、绑定设备指纹外发记录每次外发都会在数据库里留下记录施工单位打开文件时会触发一次激活后台记录激活时间和设备信息二次传播追踪如果施工单位把文件转发给第三方第三方打开时同样触发激活施工单位无法抵赖不是我传的施工单位收到外发包后打开流程打开文件 → 验证设备指纹 → 验证有效期 → 记录激活日志 → 加载水印 → 允许预览 截图操作 → 系统检测 → 弹出警告记录截图行为 转发文件 → 系统检测 → 直接阻止并记录尝试这套机制上线三个月外发记录表已经有40多万条没有发生一起图纸外泄投诉。五、踩过的坑最后说几个实际踩过的坑坑1权限继承的优先级问题一开始设计继承逻辑时我们认为子级权限优先于父级。但实际场景中父文件夹设置禁止下载子文件夹里的某个重要文件需要临时开放下载权限。后来改成显式覆盖机制——子文件夹的权限标记override_flag1时才覆盖父级权限。否则都是继承合并。坑2权限变更的实时性问题管理员在后台改了某个文件夹的权限但用户那边可能还有缓存的旧权限。最长的测试是改了权限后用户在5分钟内还能用旧权限访问文件。最终方案权限变更时通过消息队列Kafka实时推送到所有在线节点清除本地缓存。离线用户下次登录时强制刷新权限。坑3权限校验的性能问题最早期版本权限校验走数据库查询。300个用户的并发访问直接把数据库打爆。现在Redis缓存本地LRU的两级方案才算扛住了峰值。总结32维度权限体系的核心挑战不是有多少个维度而是维度之间的组合逻辑不同维度叠加后的最终权限是什么需要清晰的状态机定义继承与覆盖的优先级父子文件夹、不同主体类型之间的权限优先级必须明确性能与实时性的平衡权限校验必须快毫秒级但权限变更也必须实时生效对于设计院这类图纸安全至上的行业32维度权限体系已经能覆盖绝大多数场景。如果有更特殊的管控需求比如某几个图纸只能在指定城市的指定设备上打开在这个框架上扩展管控层维度即可。架构不怕复杂怕的是没有把复杂场景拆解成可执行的维度。