资讯动态

【A11】服务器底层权限表笔记

发布时间:2026/10/18 22:17:15 来源:尧图企业网站定制
从服务器职责出发梳理权限表的定位、结构、使用方式。服务器是权威账本 数据仓库 路由纯响应式读写与同步由客户端主导版本号由时间式机制天然承载。一、服务器职责1.1 三件事服务器只做三件事 1. 维护权限表grants谁对什么有权限 2. 存储数据values资源的字节 版本号 3. 响应请求按权限返回 / 按权限接收 / 移交仲裁不解释数据、不执行业务、不做权限计算、不主动推送。1.2 不做什么不做原因不解释 R字节内容只存 bytes不执行业务逻辑客户端负责不计算权限继承、组、角色中间环节暂不考虑最终落到 grants不主动下传纯响应式客户端请求才下发不做同步决策同步由客户端主导服务器是账本 仓库 路由不是业务处理器也不是主动推送者。1.3 与客户端的分工服务器关心设备pc_id按表响应请求 客户端关心登录人user按权限表过滤展示主导读写与同步 服务器以设备为单位纯响应 客户端以用户为单位主动驱动二、权限表grants2.1 结构CREATETABLEgrants(resourceINTEGERNOTNULL,-- 资源编号pc_idINTEGERNOTNULL,-- 设备编号levelTEXTNOTNULL,-- read | ownPRIMARYKEY(resource,pc_id));-- 一个资源只有一个写者CREATEUNIQUEINDEXidx_one_own_per_resourceONgrants(resource)WHERElevelown;-- 按设备查CREATEINDEXidx_grants_pcONgrants(pc_id);2.2 语义有记录 → 能读客户端可请求数据 levelown → 还能写是数据源隐含读权限 读有记录 有读权限客户端可请求 写levelown 写权限同时隐含读权限注意有读权限 ≠ 服务器主动下传。有读权限只是客户端可以请求。2.3 唯一性一个资源 - 多行多个读者levelread - 一行 own唯一写者levelown 由部分唯一索引保证。三、数据表values3.1 结构CREATETABLEvalues(resourceINTEGERPRIMARYKEY,kindINTEGERNOTNULL,-- 资源类型bytesBLOBNOTNULL,-- 数据字节versionINTEGERNOTNULL-- 版本号TimeId);3.2 语义kind资源类型用于客户端反序列化 bytes数据不透明服务器不解释 version版本号时间式机制单调递增3.3 版本号的来源version 直接用 TimeId - 由时间式同步机制天然承载 - 每次写产生新 TimeId - 单调递增、全局唯一、带物理时间语义 不需要额外的 u64 版本字段。四、客户端主导的读写与同步4.1 客户端做什么客户端 - 决定何时读拉取数据 - 决定何时写编辑、上传 - 决定何时同步上传本地变更、拉取更新 - 处理冲突用 version 比对 服务器 - 存数据values - 记权限grants - 响应请求pull / push / transfer - 不做决策客户端是驱动者服务器是服务者。4.2 写权限设备是数据源写权限设备 D 拥有 R - D 是数据源 - R 的数据在 D 本地产生 - D 上传给服务器备份 分发 - 平时不需要从服务器下传 - 如果服务器下传给 D反而可能覆盖更新的数据4.3 下传的场景正常情况下传写权限设备 - 无 异常下传写权限设备 1. 设备移交后首次登录 → 新 owner 需要 R 的当前数据 2. 本地数据损坏 / 丢失 → 从服务器恢复 正常下传读权限设备 - 客户端请求时下发 - 按需拉取五、下发pull客户端请求触发5.1 流程设备 D 请求数据 1. 客户端发起请求不是服务器主动 2. 查 grants WHERE pc_id D 3. 得到 D 有权限的资源 4. 查 values 拿 bytes version 5. 返回关键客户端请求才下发服务器不主动推。5.2 SQL-- D 有权限的资源有记录 有读权限SELECTresourceFROMgrantsWHEREpc_id?;-- 拿数据SELECTresource,kind,bytes,versionFROMvaluesWHEREresourceIN(SELECTresourceFROMgrantsWHEREpc_id?);5.3 增量拉取客户端请求 给我 last_sync_version 之后的变化 带 last_sync_version上次同步到的 TimeId 服务器返回 version last_sync_version 的所有变更按时间式版本增量拉取。六、接收push6.1 流程设备 D 上传资源 R 1. 查 grants WHERE resource R AND pc_id D AND level own 2. 存在 → 允许 3. 不存在 → 拒绝 4. 校验 base_version values[R].version ? - 匹配 → 接受version 新 TimeId - 不匹配 → 拒绝返回服务器最新 5. 更新 values6.2 SQL-- 校验 D 是否是 R 的写者SELECT1FROMgrantsWHEREresource?ANDpc_id?ANDlevelown;-- 校验版本 更新UPDATEvaluesSETbytes?,version?WHEREresource?ANDversion?;-- 影响行数 0 → 版本冲突写必须 level ‘own’且版本匹配。6.3 冲突处理版本冲突时 客户端收到 - 服务器最新 version - 服务器最新 bytes 客户端决定 - 合并重新编辑基于新版本 - 覆盖放弃服务器强制上传 - 放弃放弃本地冲突处理在客户端。七、移交7.1 流程移交时需要服务器 1. A 请求移交 R 给 B 2. 服务器查 grantsR 的 own 是不是 A 3. 是 → 更新 grantsR 的 own 改为 B 4. 返回成功 5. A 本地清除B 本地获得7.2 移交后的首次下传B 获得 R 的写权限后 - B 的设备上还没有 R 的数据 - B 首次登录时请求 R 的数据 - 服务器下发 R 的最新 bytes version - B 本地存储开始作为新的数据源移交后首次登录下传一次。7.3 对比操作权限来源服务器参与下传读read 设备本地缓存请求时✅ 请求触发写平时本地缓存上传时❌ 不下传写移交后首次服务器确认 下发✅ 一次性写本地损坏服务器请求恢复✅ 请求触发移交服务器✅❌八、时间式版本号8.1 版本号的本质版本号 TimeId时间式同步机制 - 单调递增 - 全局唯一 - 带物理时间语义 每次写 values[R].version 新 TimeId 不需要额外的 u64 版本字段。8.2 用途1. 冲突检测 客户端 base_version vs 服务器 version 2. 增量拉取 version last_sync_version 3. 审计 version 带时间可追溯8.3 统一一套 TimeId覆盖 - 棒 ID - 版本号 - 冲突检测 - 增量同步九、完整的服务器代码骨架pubstructServer{grants:GrantsTable,values:ValuesTable,}implServer{/// 拉取权限客户端问我能访问什么fnpull_grants(self,pc:PcId)-ResultVecGrant{self.grants.find_by_pc(pc)}/// 拉取数据客户端请求它有权访问的资源/// 客户端请求触发服务器不主动推fnpull_values(self,pc:PcId,resources:[ResourceId],since:OptionTimeId,)-ResultVecServerResource{// 校验 pc 对这些资源有权限letallowed:Vec_resources.iter().filter(|r|self.grants.has_access(**r,pc).unwrap_or(false)).collect();// 按 since 过滤增量allowed.iter().filter_map(|r|self.values.get(*r).ok()).filter(|v|since.map_or(true,|s|v.versions)).collect()}/// 接收pc 上传资源 Rfnpush(self,pc:PcId,resource:ResourceId,base_version:TimeId,bytes:Vecu8,)-ResultTimeId{// 1. 校验写权限letlevelself.grants.level_of(resource,pc)?;iflevel!Level::Own{returnErr(Error::NotOwner);}// 2. 校验版本letcurrentself.values.get(resource)?;ifcurrent.version!base_version{returnErr(Error::VersionConflict{latest:current.version,latest_bytes:current.bytes,});}// 3. 生成新版本 存储letnew_versionTimeId::next();self.values.update(resource,bytes,new_version)?;Ok(new_version)}/// 移交把 R 的写权限从 A 转给 Bfntransfer(self,actor:PcId,resource:ResourceId,new_pc:PcId)-Result(){letlevelself.grants.level_of(resource,actor)?;iflevel!Level::Own{returnErr(Error::NotOwner);}self.grants.update_owner(resource,new_pc)?;Ok(())}}四个方法pull_grants / pull_values / push / transfer全部响应式。十、中间环节暂不考虑10.1 暂不考虑暂不考虑 - 权限继承子资源继承父资源 - 组授权组可读 → 组成员可读 - 角色授权角色可读 → 角色成员可读 - 动态权限按条件计算10.2 grants 是最终形态不管权限怎么计算继承、组、角色 最终都落到 grants 表 (resource, pc_id, level) 服务器只认 grants。10.3 先跑通第一步 - grants 表手动维护 - pull_grants / pull_values / push / transfer - 时间式版本号 - 跑通 第二步 - 加继承、组、角色 - 自动生成 grants十一、一句话服务器是权威账本 数据仓库 路由维护 grants权限和 values数据 版本纯响应式。读写与同步由客户端主导写权限设备是数据源平时不下传移交后首次登录、本地损坏时才下传。版本号由时间式同步机制TimeId天然承载一套机制覆盖棒 ID、版本、冲突检测、增量同步。grants 是权限的最终形态中间环节暂不考虑。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑