news 2026/9/13 16:59:57

Label Studio Redact Annotator PII 插件:基于 whoami 角色鉴权的标注者身份脱敏方案

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Label Studio Redact Annotator PII 插件:基于 whoami 角色鉴权的标注者身份脱敏方案

Label Studio Redact Annotator PII 插件:基于 whoami 角色鉴权的标注者身份脱敏方案

【免费下载链接】label-studioLabel Studio is a multi-type data labeling and annotation tool with standardized output format项目地址: https://gitcode.com/GitHub_Trending/la/label-studio

Label Studio 提供了一款名为Redact Annotator PII的标注接口插件,用于在标注流与审核流中隐藏标注者的姓名、头像和日期等个人可识别信息(PII),从而降低多人协作标注中的身份偏见,并仅在用户为组织管理员时自动恢复可见性。本文以官方插件文档 Redact Annotator PII 为主线,完整给出其 Labeling 配置、插件脚本与示例数据,并结合开源仓库中whoami接口的真实实现(用户 URL 注册、接口实现),解析这套"CSS 默认隐藏 + 脚本按角色解禁"的脱敏机制底层原理。读完后,你将能够:为项目配置一套可复制运行的 PII 脱敏方案,并理解角色判定、样式移除等关键细节在源码中的落点。

插件定位与双层工作原理

该插件面向的核心场景是:当多个标注者在同一批任务上产出标注时,标注者之间可能因为知道"这条标注是谁做的"而产生从众、权威效应等偏见;在审核(Review)阶段,审核者知道被审标注的作者身份同样会引入偏差。因此该插件的目标是对普通标注者/审核者匿名化标注者信息,同时对管理员保留完整信息以便追溯

从文档给出的实现看,整套方案由两层机制配合完成:

  1. Labeling 配置层(默认隐藏):通过<Style>标签注入 CSS,把标注按钮上的用户名、头像、日期,以及评论、标注历史中的人名/日期/头像元素的display全部置为none。这一层不依赖任何脚本,只要配置生效,所有用户在标注流与审核流中看到的 PII 都是被遮蔽的。
  2. 插件脚本层(按角色恢复):JavaScript 插件在每次标注展示时执行,通过平台的whoami接口获取当前登录用户的组织角色;如果角色是管理员(枚举值AD),就移除 Labeling 配置中注入的<Style>节点,从而"反隐藏"PII。

需要说明的是,该文档在 front-matter 中标记为tier: enterprise,即这一完整能力在 HumanSignal/Label Studio Enterprise 的产品语境下提供;文档中脚本硬编码了 SaaS 域名的 whoami 地址,自建部署时对应的是站点自身的/api/current-user/whoami路径(下文结合源码说明)。插件本身的编写规范——包括事件订阅、LSI接口对象与调试面板——参见 Customize and Build Your Own Plugins;插件的通用背景与常见问题可查 Plugins for projects 与 Plugin FAQ。

Labeling 配置:用 CSS 在标注/审核流中隐藏 PII

文档给出的完整 Labeling 配置如下,这是一个"文本情感分类"示例:最外层<View>通过idAttr="noPII"给整个视图容器打上noPII属性(供脚本定位),内部<Style>负责遮蔽 PII 元素,业务部分则是Text展示加单选Choices:

<View idAttr="noPII"> <Style> .lsf-annotation-button__user { display: none; } .lsf-userpic { display: none; } .lsf-annotation-button__userpic { display: none } .lsf-annotation-button__date { display: none; } .lsf-comment-item__name { display: none; } .lsf-comment-item__date { display: none; } .lsf-comment-item__userpic { display: none; } .lsf-history-item__name { display: none; } .lsf-history-item__date { display: none; } </Style> <Text name="text" value="$text" /> <View style="box-shadow: 2px 2px 5px #999; padding: 20px; margin-top: 2em; border-radius: 5px;"> <Header value="Choose text sentiment" /> <Choices name="sentiment" toName="text" choice="single" showInLine="true"> <Choice value="Positive" /> <Choice value="Negative" /> <Choice value="Neutral" /> </Choices> </View> </View>

这组 CSS 选择器覆盖了三类界面元素,可整理为如下对应关系:

选择器隐藏的对象
.lsf-annotation-button__user标注/审核按钮上显示的用户名
.lsf-userpic.lsf-annotation-button__userpic各处头像图片
.lsf-annotation-button__date标注按钮上的操作日期
.lsf-comment-item__name.lsf-comment-item__date.lsf-comment-item__userpic评论区中的评论者姓名、时间与头像
.lsf-history-item__name.lsf-history-item__date标注历史条目中的作者名与时间

其中idAttr="noPII"的作用是把noPII这个属性写到根<View>渲染出的 DOM 元素上,使插件脚本能够用document.getElementById('noPII')精确找到这段配置所渲染出的容器,再删除它下面的<Style>子节点——这是"CSS 隐藏"与"脚本解禁"两层之间唯一的衔接点。相关标签的用法详见 View、Style、Text、Header、Choices。

插件脚本:基于 whoami 的角色化恢复

文档提供的完整插件脚本如下:

/* Hide annotator personal information (PII) if the logged user is not an Admin */ /** * Fetch currently logged user via the HumanSignal API */ async function fetchUserInfo() { const whoamiUrl = "https://app.humansignal.com/api/current-user/whoami"; const response = await fetch(whoamiUrl, { method: 'GET', headers: { 'Content-Type': 'application/json', // No Auth `credentials` needed for `same-origin` given Session-Based Authentication is used in the API } }); if (!response.ok) { throw new Error(`Error: ${response.status} ${response.statusText}`); } const data = await response.json(); return data; } /** * Give visibility to the given selector */ function displayEl(sel) { const els = document.querySelectorAll(sel); if (els) { els.forEach(function (el, idx) { el.style.display = "block"; }); } } /** * If the logged in user is an Admin, remove the styling added to the view that hides * the annotator identity */ async function hidePII() { let user, role try { const userInfo = await fetchUserInfo(); user = userInfo.username || 'Unknown'; role = userInfo.organization_membership.role || 'Unknown'; } catch (error) { Htx.showModal(`Error fetching user information: ${error.message}`); } if (!user) { console.warn("Did not find a username and it was not 'Unknown'"); return; } if (role === 'AD') { // console.log("Role is admin; displaying PII"); // If admin, remove the nulled Style tag const firstChild = document.getElementById('noPII').firstChild; if (firstChild.tagName === 'STYLE') { firstChild.remove(); } } } (async () => { await hidePII(); })();

脚本的执行链条可以拆解为四步:

  1. fetchUserInfo():向 whoami 接口发起 GET 请求。按注释说明,由于该接口使用基于 Session 的认证且请求为同源的,浏览器会自动携带会话凭证,无需额外credentials配置;非 2xx 响应会抛错进入catch
  2. hidePII():从响应中取出usernameorganization_membership.role两个字段,分别兜底为'Unknown'。如果拉取失败,通过Htx.showModal弹出错误提示(这是插件运行环境中可用的界面提示能力)。
  3. 角色判定:仅当role === 'AD'时才执行恢复逻辑。
  4. 样式移除:定位noPII容器的第一个子节点,确认其是STYLE标签后调用remove()将其从 DOM 中删除——注意是移除整个 Style 节点而非逐条改回display,因此恢复效果干净彻底。非管理员用户则不做任何操作,PII 保持 CSS 遮蔽状态。脚本末尾的 IIFE(async () => { await hidePII(); })();使整个流程在插件被调用时异步自执行,契合插件运行在异步上下文、可使用await的执行模型。

另外,脚本中保留了一个未参与主流程的displayEl(sel)工具函数,用于把指定选择器的元素重新设为display: block;它体现了一种备选恢复思路(逐个恢复元素),而当前主实现选择的是整块移除Style

whoami 接口在仓库源码中的落点

文档脚本里写死了 SaaS 域名https://app.humansignal.com/api/current-user/whoami;对于自建部署,对应的就是本仓库中注册的同名路径。在 users/urls.py 中可以看到该路由:

path('api/current-user/whoami', api.UserWhoAmIAPI.as_view(), name='current-user-whoami'),

其视图实现见 users/api.py:UserWhoAmIAPI继承自generics.RetrieveAPIView,要求IsAuthenticated,get_object直接返回request.user,即以当前会话用户作为查询对象,响应由WhoAmIUserSerializer序列化。该序列化器在 users/serializers.py 中定义为BaseWhoAmIUserSerializer,在基础用户字段之上额外附带了permissions字段:

class BaseWhoAmIUserSerializer(BaseUserSerializer): permissions = serializers.SerializerMethodField() class Meta(BaseUserSerializer.Meta): fields = BaseUserSerializer.Meta.fields + ('permissions',) def get_permissions(self, user) -> list[str]: return [perm for _, perm in all_permissions]

脚本读取的usernameorganization_membership.role正是这一用户序列化输出的一部分。而role === 'AD'这个判定依据的角色枚举,在 core/settings/base.py 的 OpenAPI 枚举定义中可以得到印证:OrganizationRoleEnum包含OW(Owner)、AD(Administrator)、MA(Manager)、RE(Reviewer)、AN(Annotator)、DI(Deactivated)、NO(Not Activated)、VO(View Only),其中AD即文档脚本中用于判定"管理员"的取值。此外,前端模板(如 users/user_account.html)也通过{% url 'current-user-whoami' %}调用同一接口,说明 whoami 是平台内通用的"我是谁"查询入口,插件只是复用了它。

示例数据

文档配套了三条文本分类样例,与 Labeling 配置中的$text字段对应,可直接用于导入测试:

[ { "data": { "text": "I recently purchased a portable Bluetooth speaker and have been impressed with its clear sound and long battery life. The speaker is compact and easy to use, making it perfect for outdoor adventures." } }, { "data": { "text": "I bought a smartwatch from this vendor and it has exceeded my expectations. The device offers an intuitive user interface and tracks my daily activities accurately while looking very stylish on my wrist." } }, { "data": { "text": "I ordered a pair of noise-cancelling headphones and they don't do anything to cancel out noise. Waste of money." } } ]

配置上述 Labeling 配置与示例数据后:普通标注者/审核者进入标注流与审核流时,标注按钮、评论区与标注历史中的用户名、头像、日期均不可见;管理员进入同一界面时,Style节点被插件移除,身份信息完整可见。

适用边界与限制

文档特别强调了几条边界,配置该方案前应明确:

  • 遮蔽范围有限:Labeling 配置中的 CSS 只作用于标注流与审核流界面,不会遮蔽 Data Manager(数据管理界面)中的标注者信息。若需要连 Data Manager 也限制访问,文档建议通过 项目设置 禁止 Annotator 与 Reviewer 角色访问 Data Manager,从权限层面补齐。
  • whoami 地址随部署形态变化:文档脚本中的 whoami URL 是 HumanSignal SaaS 域名,依赖同源会话认证;自建部署时应把该 URL 指向自身站点的/api/current-user/whoami路径(路由定义见 users/urls.py),否则会因跨域或域名不存在导致fetch失败并弹出错误提示。
  • 执行模型:按 自定义插件文档 的说明,插件在每次标注展示时都会执行一次(打开任务、切换任务/标注、查看历史版本等场景)。本插件的恢复逻辑是幂等的——非管理员路径不操作 DOM,管理员路径删除的是"当前这一次渲染"中的Style节点,下一次标注展示时 DOM 重新渲染、脚本重新执行,天然不会累积副作用;但如果你要在此基础上扩展(例如用displayEl逐元素恢复),仍需遵循"避免重复订阅事件、做好运行间清理"的插件开发规范。
  • 角色判定仅识别AD:当前脚本只把AD(Administrator) 视为可见 PII 的角色,OW(Owner)、MA(Manager) 等其他角色同样会被遮蔽;如需扩大解禁范围,需要自行扩展role的判定条件。

参考与延伸阅读

  • 插件文档主体:Redact Annotator PII
  • 插件开发与调试(Testing 面板、LSI接口、debugger):Customize and Build Your Own Plugins
  • 插件总览与安全注意事项:Plugins for projects
  • 插件 FAQ:Plugin FAQ
  • 前端界面事件与结构参考:Frontend reference
  • 源码证据:whoami 路由、UserWhoAmIAPI、BaseWhoAmIUserSerializer、组织角色枚举

【免费下载链接】label-studioLabel Studio is a multi-type data labeling and annotation tool with standardized output format项目地址: https://gitcode.com/GitHub_Trending/la/label-studio

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/13 16:58:48

手写User-Based协同过滤推荐系统:从稀疏矩阵到前端展示全链路实现

简介&#xff1a;本资源是一套完整的基于Python的协同过滤推荐算法电影推荐系统&#xff0c;专为计算机相关专业本科生毕业设计、课程设计及项目实战学习者打造&#xff0c;有效解决推荐系统原理理解与工程落地脱节问题。压缩包共1197个文件&#xff0c;含22个核心Python源码文…

作者头像 李华
网站建设 2026/9/13 16:58:28

UnoCSS Autocomplete 完全指南:为原子化 CSS 打造智能补全

UnoCSS Autocomplete 完全指南&#xff1a;为原子化 CSS 打造智能补全 【免费下载链接】unocss The instant on-demand atomic CSS engine. 项目地址: https://gitcode.com/GitHub_Trending/un/unocss UnoCSS 的 Autocomplete 是一套面向智能提示的可定制机制&#xff0…

作者头像 李华
网站建设 2026/9/13 16:55:27

PDF补丁丁:开源PDF书签编辑与文档合并指南

PDF补丁丁&#xff1a;开源PDF书签编辑与文档合并指南 【免费下载链接】PDFPatcher PDF补丁丁——PDF工具箱&#xff0c;可以编辑书签、剪裁旋转页面、解除限制、提取或合并文档&#xff0c;探查文档结构&#xff0c;提取图片、转成图片等等 项目地址: https://gitcode.com/G…

作者头像 李华
网站建设 2026/9/13 16:54:55

Ollama API 全量响应SDK实战教程:流式/非流式对接、异常处理与生产落地

本地大模型落地的核心痛点从来不是模型运行&#xff0c;而是接口标准化对接。很多开发者搭建完Ollama本地模型环境后&#xff0c;只会用官方简单示例代码&#xff0c;无法区分流式与非流式响应逻辑&#xff0c;不懂异常捕获、参数调优、多轮对话封装&#xff0c;上线后频繁出现…

作者头像 李华