Front-End-Checklist 实战:按 GDPR 第 17 条实现用户数据删除机制(Right to Erasure)
Front-End-Checklist 实战按 GDPR 第 17 条实现用户数据删除机制Right to Erasure【免费下载链接】Front-End-Checklist The essential checklist for modern web development, for humans and AI agents项目地址: https://gitcode.com/gh_mirrors/fr/Front-End-Checklist本文以 Front-End-Checklist 仓库中的 right-to-erasure 规则文档references/rule.md 与 SKILL.md为主体系统讲解面向用户的数据删除机制应如何设计从账户设置里的删除入口、两步确认交互到localStorage/sessionStorage/IndexedDB/Cookie/Service Worker 缓存的全面清理再到服务端删除 API 与 30 天期限的落地。读完本文你将能依据 GDPR Article 17 在自己的前端应用中实现一套完整、可审计、可通过验证清单的自助删除流程。一、什么是被遗忘权GDPR 第 17 条为什么关乎前端被遗忘权Right to erasure / Right to be forgotten是 GDPR《通用数据保护条例》第 17 条赋予欧盟境内用户的核心权利当个人数据不再为收集目的所必需或用户撤回同意时数据控制者controller必须应请求删除其个人数据除非存在继续处理的法定理由。对前端应用而言这一义务天然地分为两个维度清除全部客户端存储——浏览器里散落的localStorage、sessionStorage、IndexedDB、Cookie、Service Worker 缓存触发服务端删除——向删除 API 发起请求让服务器在 30 天内完成数据清除。原文档特别强调了一个合规动机不履行这一权利可能招致最高2000 万欧元或全球年营业额 4%的监管罚款。与此同时一个清晰、可发现的删除流程本身就是建立用户信任的关键体验属于隐私质量检查清单中的核心项。在仓库中这条规则被编排在 packages/content/rules/en/privacy/right-to-erasure.mdx归属于privacy分类下的data-rights子类优先级 medium、难度 intermediate、预估耗时 60 分钟同时它也是 Privacy Consent 检查清单 的组成规则之一并在 README.md 的整体清单中作为可勾选项出现。二、入口设计与两步确认删除选项必须可被发现删除机制的第一步是用户能找到它。原文档给出的设计原则是把删除入口放在账户设置Account Settings中并置于诸如 Privacy 或 Your data 这样语义清晰的分区之下同时为避免误触导致数据被意外清除必须采用两步确认模式——用户先点击入口进入确认态再显式点击确认按钮才真正执行。// DeletionRequestButton.tsx import { useState } from react; import { clearUserData } from /lib/privacy; type DeletionState idle | confirming | pending | done | error; export function DeletionRequestButton() { const [state, setState] useStateDeletionState(idle); async function handleConfirm() { setState(pending); try { // 1. Clear all client-side storage immediately clearUserData(); // 2. Send deletion request to the server const response await fetch(/api/account/delete, { method: POST, headers: { Content-Type: application/json }, }); if (!response.ok) throw new Error(Server deletion request failed); setState(done); } catch { setState(error); } } if (state done) { return ( p rolestatus Your deletion request has been received. Your data will be removed within 30 days. You have been signed out. /p ); } if (state confirming) { return ( div rolealertdialog aria-labelledbydelete-confirm-title h2 iddelete-confirm-titleDelete your account and all data?/h2 pThis action cannot be undone. You will be signed out immediately./p button onClick{handleConfirm} disabled{state pending} {state pending ? Deleting… : Yes, delete my data} /button button onClick{() setState(idle)}Cancel/button /div ); } return ( button onClick{() setState(confirming)} Delete my account and data /button ); }这个组件用状态机idle → confirming → pending → done / error管理整个删除流程有三处值得注意的细节确认对话框使用rolealertdialog与aria-labelledby这不是普通的弹窗而是语义化的模态告警屏幕阅读器用户能明确感知这是需要决断的删除操作完成态使用rolestatus删除请求受理后辅助技术可以播报这一状态变化pending状态禁用按钮防止重复提交同时按钮文案切换为 Deleting… 给予即时反馈。从源码结构看原文档在 right-to-erasure.mdx 中为该示例补全了import与组件导出删除了引用文档中的残缺片段使其成为可直接编译运行的完整组件。三、必须删除什么数据存放位置的完整清单一次合规的删除必须覆盖所有可能存放个人数据的位置。原文档给出了一张存放位置 → 清理 API的对照表这是实施时逐项核对的地图存放位置清理 APIlocalStoragelocalStorage.clear()或按 key 调用removeItemsessionStoragesessionStorage.clear()IndexedDBindexedDB.deleteDatabase(name)Cookies将每个 Cookie 设置为Max-Age0; expiresThu, 01 Jan 1970Service Worker 缓存caches.delete(cacheName)服务端数据向删除 API 发起 DELETE / POST 请求值得注意的是这张表把服务端数据也并列纳入——客户端清理只是删除机制的一半任何只做了前端清理、却把个人数据留在服务器上的实现都不能算作满足 GDPR 第 17 条。四、clearUserData()把客户端清理收敛为一个可审计函数原文档强烈建议把客户端所有存储机制的清理逻辑集中到一个clearUserData()函数中。集中化的收益是可审计、可扩展审查者只需查看这一个函数就能确认所有存储位置都被覆盖未来新增存储类型时也只需在此扩展。// lib/privacy.ts /** * Removes all personal data from client-side storage. * Call this immediately when a deletion request is confirmed — do not wait * for the server response, as the user has already expressed intent to delete. */ export async function clearUserData(): Promisevoid { // 1. localStorage localStorage.clear(); // 2. sessionStorage sessionStorage.clear(); // 3. IndexedDB — delete every database the application has created const databases await indexedDB.databases(); await Promise.all( databases.map((db) { if (!db.name) return Promise.resolve(); return new Promisevoid((resolve, reject) { const req indexedDB.deleteDatabase(db.name!); req.onsuccess () resolve(); req.onerror () reject(req.error); }); }) ); // 4. Cookies — clear known application cookies const cookiesToDelete [session, refresh_token, user_prefs, __stripe_mid]; for (const name of cookiesToDelete) { document.cookie ${name}; Max-Age0; path/; SameSiteLax; } // 5. Cache Storage (Service Worker caches) if (caches in window) { const cacheNames await caches.keys(); await Promise.all(cacheNames.map((name) caches.delete(name))); } }几个需要展开的实现细节IndexedDB 的删除是异步且逐个进行的先通过indexedDB.databases()枚举所有数据库注意该 API 可能返回空name的占位项需要过滤再用Promise包装deleteDatabase的成功/失败回调最后以Promise.all并行等待全部完成。deleteDatabase返回的是IDBOpenDBRequest其onsuccess/onerror是回调式 API必须手动转成 Promise 才能与async/await协作。Cookie 无法枚举只能按已知名单逐个清除document.cookie只能写入而不能读取所有 Cookie 的完整列表HttpOnly的 Cookie 更是不可见因此需要一个cookiesToDelete应用白名单。示例中给出的session、refresh_token、user_prefs、__stripe_mid覆盖了会话、令牌、偏好与第三方支付标记四类典型场景实际项目中应替换为应用真实使用的 Cookie 名单。Service Worker 缓存需要能力检测caches in window的守卫确保在不支持 Cache Storage API 的环境中不抛错caches.keys()返回所有缓存名逐个caches.delete()后同样用Promise.all并行处理。原文档还给出了一条重要的时序纪律在 right-to-erasure.mdx 中以 Warning 形式强调不要等服务端响应后再清理客户端数据。应在确认删除意图后立即清除本地数据。即使网络请求失败用户的本地数据也已消失——这是正确的行为。服务端调用的重试与本地清理是两件独立的事。五、服务端删除 API接受请求并纳入 30 天窗口客户端清理只解决了浏览器侧服务端必须接收删除请求并在 GDPR 规定的 30 天内异步完成处理。原文档给出的 Next.js App Router 路由实现如下// app/api/account/delete/route.ts (Next.js App Router) import { NextResponse } from next/server; import { getServerSession } from next-auth; export async function POST() { const session await getServerSession(); if (!session?.user?.id) { return NextResponse.json({ error: Unauthenticated }, { status: 401 }); } // Queue deletion — process asynchronously within 30 days await scheduleDeletion({ userId: session.user.id, requestedAt: new Date().toISOString(), // GDPR deadline: 30 calendar days from request deadline: new Date(Date.now() 30 * 24 * 60 * 60 * 1000).toISOString(), }); // Send confirmation email to the address on record before it is deleted await sendDeletionConfirmationEmail(session.user.email); return NextResponse.json({ received: true }); }实现要点拆解身份校验先行getServerSession()拿不到会话未登录时立即返回401删除接口必须拒绝匿名调用否则会成为任意用户的删除攻击面采用排队 异步处理而非同步删除scheduleDeletion()把删除任务连同requestedAt与计算好的deadlineDate.now() 30 * 24 * 60 * 60 * 1000即 30 个日历日写入队列由后台任务在窗口内完成删除。这样即便数据量大、涉及多个系统也不会阻塞用户请求在数据被删前发送确认邮件sendDeletionConfirmationEmail(session.user.email)必须在删除发生之前调用——这是唯一仍能联系到用户的时机同时也为用户留存了受理凭证幂等的受理响应{ received: true }表示已受理而非已删除完成语义上准确地区分了请求接收与最终执行。六、确认与时间线沟通让用户知道接下来会发生什么删除请求提交后原文档要求向用户明确传达四类信息请求已被受理request has been received数据将在什么期限内被移除例如 within 30 days用户已从所有设备登出signed out of all devices一个可供留存记录的参考号reference number如果系统支持。这四项沟通内容其实也是前文DeletionRequestButton完成态文案Your deletion request has been received. Your data will be removed within 30 days. You have been signed out.的落点受理确认 30 天期限 登出提示三者缺一不可。第三方数据处理者删除请求必须转发原文档以 Warning 形式单独强调了第三方处理器问题应用很可能把个人数据传递给分析analytics、CRM、邮件工具等第三方处理器删除请求必须同步转发给这些处理器。每个处理器的 API 都应检查其删除端点并把相应调用纳入删除工作流。常见做法是维护一张处理器 → 删除端点的清单在scheduleDeletion的后台任务中逐一遍历调用——这与前文每个处理器 API 检查删除端点的建议互为表里。七、与关联规则的协作数据最小化是删除的减负在规则体系中right-to-erasure 并非孤立存在。right-to-erasure.mdx 的 frontmatter 声明了三条关联规则其中与删除机制最互补的是 contenteditable="false">【免费下载链接】Front-End-Checklist The essential checklist for modern web development, for humans and AI agents项目地址: https://gitcode.com/gh_mirrors/fr/Front-End-Checklist创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考