Skip to content
bitzorcas
中EN

Concept

GDPR 与数据主体权利

源码校验的 GDPR 模块说明书,覆盖同意、SAR、擦除、租户隔离、持久化、权限、证据与生产缺口。

Last updated

GDPR 模块管理同意历史、数据主体访问请求(SAR)和擦除请求。它已经具备双 ORM 持久化、30 天擦除冷静期、租户谓词和 Identity 用户匿名化,但还不是完整的商业合规编排平台。

1. 当前端到端路径

已认证用户

生成式 /api/privacy/* 端点

Mediator 管道
认证 / 授权 / 事务 / Activity 审计

GDPR Commands / Queries

IGdprStore

SysDataSubjectRequest

SysConsent

IAuditQueryPort
SAR 仅取第一页

IIdentityPersonalDataEraser
仅处理 SysUser

所有 [GenerateEndpoint] 路由默认 RequireAuthorization()。实现了 IAuthorizedRequest 的命令还会进入框架授权决策;普通查询和 RecordConsent 只受 HTTP 认证保护。

2. 当前能力矩阵

能力当前实现不能推断出的保证
同意授权追加 SysConsent 历史行没有目的目录、文本快照、唯一活动同意或下游传播
同意撤回本人或角色名 admin 设置 RevokedAt没有撤回事件和处理方确认
SAR 创建租户内按 RequestId 先查后插入没有数据库唯一约束,并发不保证幂等
SAR 处理保存 UserId 与最多 1000 条审计项没有业务模块收集、文件、下载、加密或过期
擦除创建创建 30 天 CoolingOff 请求没有身份再验证、审批或法律保全
擦除执行匿名化并软删除当前租户的 SysUser 行不覆盖凭据、会话、业务模块和外部处理方
持久化ORM 中立 IEntitySet<T>,SqlSugar/EF Core 契约测试不等于完整工作流语义已验证
活动审计通用 Activity 管道记录命令结果是 best-effort,不是不可变合规证据账本

3. HTTP 用例与实际授权

方法与路由用例额外授权决策
POST /api/privacy/consentsRecordConsent无 IAuthorizedRequest
GET /api/privacy/consentsGetConsents无 IAuthorizedRequest
DELETE /api/privacy/consents/{id}RevokeConsentgdpr.own-data.delete
POST /api/privacy/sarCreateSargdpr.own-data.create
GET /api/privacy/sarGetSarRequests无 IAuthorizedRequest
POST /api/privacy/sar/{id}/processProcessSarprivacy.sar.update
POST /api/privacy/erasureCreateErasuregdpr.own-data.create
DELETE /api/privacy/erasure/{id}CancelErasuregdpr.own-data.delete
POST /api/privacy/erasure/{id}/executeExecuteErasureprivacy.erasure.delete

表中的决策码由 ResourceDescriptor + AuthorizationAction 推导。源码目录声明的是 privacy.consent.view、privacy.consent.manage、privacy.sar.manage 和 privacy.erasure.manage,两组并不一致。这不是命名偏好,而是可能导致权限无法分配或请求始终不获 Allow 的交付缺口。

4. 两个状态机,共用一张表

SARErasureretryafter 30 days

Submitted

Processing

Completed

Failed

Rejected

CoolingOff

Cancelled

Executing

这是业务意图,不是当前强约束。两个 SmartEnum 都以整数保存到 StatusCode,而按 ID 读取和处理器没有验证 RequestType。错误端点拿到另一类请求时,同一个整数会被解释成另一套状态,必须在生产启用前修复并加入数据库/应用层防线。

5. 租户数据面

GdprStore 使用 ICurrentTenant.Tenant.EffectiveTenantId 作为最终谓词,这是正确的存储防线。应用处理器却普遍把 currentUser.User.TenantId 作为查询参数和请求上下文:

调用方与 Store 的双重租户约束
var actorTenant = currentUser.User.TenantId;
// Store 同时要求调用方租户和当前有效租户相等。
var rows = await store.GetConsentsByUserAsync(
actorTenant,
currentUser.User.UserId?.ToString() ?? "0",
cancellationToken);
// operate-as 时 actorTenant 与 EffectiveTenantId 可能不同,因此结果为空;
// 创建路径又会以 EffectiveTenantId 落库,形成调用上下文分歧。

普通用户请求下两者通常一致;平台代操作、后台任务和租户模拟必须单独测试,不能据此宣称全场景租户正确。

6. 持久化与组合

模块拥有两张软删除租户表:

  • SysConsent:同意目的、版本、授予/撤回时间,以及当前没有写入的 IP、User-Agent 字段。
  • SysDataSubjectRequest:请求类型、状态、冷静期、拒绝原因、DetailsJson 和预留 ExportFileId。

GdprStore 不依赖 SqlSugar 或 EF Core,而依赖 IEntitySet<T>。生产配置满足数据库与 RabbitMQ 前置条件时,生成式注册选择当前 ORM Adapter;Shell 模式保留显式 Unavailable Port,调用时失败关闭。

7. 当前最重要的交付缺口

  1. SAR 与 Erasure 的处理器不校验请求类型,状态整数可以被交叉解释。
  2. RequestId 查询不包含请求类型,表上也没有唯一索引;跨类型复用和并发创建都可能出错。
  3. SAR 的 Failed 更新随后返回 Result.Failure,会被事务管道回滚,失败状态并不会持久化。
  4. ExportFileId 只有字段和测试赋值,业务代码从未生成或交付文件。
  5. 擦除只处理 SysUser 的部分字段,不会编排其他数据归属模块或外部处理方。
  6. 权限目录、Feature privacy.operations 与实际请求决策没有闭环证据。
  7. 没有主体身份再验证、法律保全、截止日期、升级通知、下载授权和逐步骤不可变证据。

8. 推荐阅读路径

  1. 同意与证据:授权、撤回、版本和证据字段。
  2. SAR 与导出:当前数据内容、分页、失败语义和目标收集器。
  3. 擦除工作流:冷静期、Identity 匿名化和归属模块编排。
  4. 存储、安全与权限:表结构、租户、权限和事务。
  5. 测试与运营:契约测试、指标、排障和 GA 门禁。

关联基础章节:Auditing、Identity、Multitenancy 和 Authorization。

9. 最小源码审查

Terminal window
# 列出全部 GDPR 用例和路由。
rg -n "GenerateEndpoint|class Handler" src/Platform/Gdpr -g '*.cs'
# 找出声明后没有形成业务写入的导出字段;生产代码应只有读取/映射命中。
rg -n "ExportFileId|DetailsJson" src/Platform/Gdpr tests -g '*.cs'
# 检查权限资源是否仍混用 gdpr 与 privacy。
rg -n 'new\("gdpr"|GdprPermissions\.' src/Platform/Gdpr -g '*.cs'

返回平台模块目录

100%

滚轮或按钮缩放 · 放大后拖动画面 · 双击切换 100% / 200%