Portal Passkey

Odoo 门户 Passkey 管理为什么重点不在登录,而在认证资产治理:自助绑定、设备命名与撤销边界讲透

很多人以为 auth_passkey_portal 只是把后台 Passkey 能力搬到门户页,但官方源码真正处理的是“已登录的门户用户何时还能安全管理认证资产、删除凭据后旧会话是否继续可信、设备命名与凭据所有权如何避免越权”。本文沿着模板、前端交互、auth_passkey 核心模型与测试用例,把这条自助治理链路讲透。

框架
进阶 开发者 2 分钟阅读
0 评论 0 点赞 0 收藏 6 阅读

先说结论

auth_passkey_portal 不是“把后台的 Passkey 弹窗搬到 /my/security”这么简单。

views/templates.xmlstatic/src/js/passkeys_portal_create.jsstatic/src/js/passkeys_portal.js,再顺着 auth_passkey/models/auth_passkey_key.pyres_users.py 往下看,官方真正处理的是三层问题:

  1. 门户用户是否真的还是“当前这个人”。
  2. 浏览器刚注册出来的凭据能不能安全挂到当前账号。
  3. 用户删掉或新增 Passkey 之后,旧 session 还能不能继续被信任。

所以这套能力的本质不是“多一个登录方式”,而是:

让低权限的 portal 用户也能安全地自助管理认证凭据,同时不把账号接管风险带进来。


Portal 侧为什么不直接开放 CRUD

templates.xml 只是在 portal.portal_my_security 里插入了一块 Passkeys 区域:

  • 展示名称、创建时间、最后使用时间
  • 提供 Rename / Delete
  • 提供 Add Passkey

表面上看,这很像普通资料页的列表管理。但真正关键的是:每个危险动作都没有直接裸调 ORM

原因很简单:门户用户虽然有自己的账号,但并不代表他当前这个会话仍然可信。一个常见误解是:

  • 既然已经登录了 portal
  • 那我当然可以顺手增删认证器

源码明显不这么想。Odoo 把“改认证凭据”视为高风险动作,必须重新校验身份。

这就是为什么前端无论创建还是删除,都要经过 handleCheckIdentity(...)。它不是多余的 UX,而是把“普通已登录态”和“允许修改认证要素的高信任态”分开。

新增 Passkey:先复核身份,再启动 WebAuthn 注册

passkeys_portal_create.js 的主链路很清楚:

  1. 用户点击 Add Passkey
  2. 前端先调用 res.users.action_create_passkey
  3. 这个调用被 handleCheckIdentity() 包住。
  4. 后端返回 registration options 后,浏览器才执行 startRegistration(serverOptions)
  5. 前端创建一个临时 auth.passkey.key.create 记录。
  6. 再调用 make_key(registration) 完成落库。

这里最容易被忽略的点,是WebAuthn 注册并不是第一步

第一步其实是 check_identity

这说明 Odoo 设计者非常清楚:如果当前 portal 会话只是被别人借用了电脑、共享了浏览器、或者 session 泄漏了,那么“允许它直接新增 passkey”就等于让攻击者为自己绑定一个长期登录入口。

因此真正的顺序不是:

  • 点击按钮
  • 注册设备
  • 成功

而是:

  • 先证明你还是账号本人
  • 再允许浏览器发起注册挑战
  • 再把新 credential 挂到你的账号上

这个顺序,就是 portal 场景和普通 WebAuthn demo 最大的区别。

make_key() 为什么要重新计算 session token

auth_passkey_key.py 里的 make_key() 很值得细看。

它做了几件事:

  • 从 session 里拿 challenge
  • 校验浏览器回传的 registration response
  • 通过 res.users.auth_passkey_key_ids 创建新 key
  • 直接写入 credential_identifierpublic_key
  • 最后重新计算 request.session.session_token

最后这一步很多人第一次看会觉得“有点绕”。

但它其实是在解决一个非常现实的问题:

会话签发时看到的用户认证要素集合,和现在数据库里的认证要素集合,已经不一样了。

如果 session token 不刷新,那么服务端就可能继续拿着“旧认证状态”看待这个会话。Odoo 通过把 auth_passkey_key_ids 纳入 session token 字段,确保新增或删除 passkey 后,当前会话的信任快照会同步更新。

这不是性能细节,而是安全边界。

删除 Passkey:重点不是删掉记录,而是避免“删错对象”

passkeys_portal.js 里删除动作同样走 handleCheckIdentity(),后端对应的是 action_delete_passkey()

这个方法的关键点有两个:

  • 只允许删除 create_uid == self.env.user.id 的 key
  • 删除后再次重算 session token

也就是说,Portal 场景下真正危险的不是“不会删”,而是:

  1. 是否可能删到别人的凭据
  2. 删完后当前会话的可信状态有没有同步变化

源码专门通过 create_uid 做所有权边界,不是依赖前端传来的用户 ID,也不是仅靠 portal 页面上只展示自己的数据。因为前端展示永远不等于后端授权。

配套测试 test_portal_permissions 更直接:portal 用户尝试改管理员 passkey,会抛 AccessError。这就是官方在测试层明确锁住的越权场景。

Rename 看起来最轻,为什么也值得关注

重命名似乎只是体验问题,但 passkeys_portal.js 仍然通过 ORM 写 auth.passkey.key,而不是把它当成前端本地标签。

这意味着 passkey name 在 Odoo 里不是纯浏览器侧备注,而是账号凭据资产的一部分。它要满足两个目标:

  • 用户自己能认出“这是公司电脑上的 Windows Hello,还是手机上的 iCloud Keychain”
  • 平台还能维持记录级权限约束

所以 rename 虽然没有 delete 那么危险,但它依然被纳入同一条“用户只能改自己的 key”边界内。认证资产一旦进入数据库,就必须服从对象权限,而不能因为“只是名字”就降低规则。

门户 Passkey 真正解决的是“弱密码之后”的长期治理

很多团队把 portal 安全只理解成:

  • 登录页加密码复杂度
  • 忘记密码发邮件
  • 高风险页面加二次确认

但 passkey portal 的意义在于,它把认证治理能力下放到了终端用户自助层。

一旦用户可以在 /my/security

  • 新增自己的 passkey
  • 给不同设备命名
  • 删除丢失设备的凭据

那安全团队就不需要每次都介入“换手机了怎么办”“旧电脑丢了怎么办”这类运营动作。

可与此同时,Odoo 也没有把这个自助流程做成“只要你还在线就能改”。它坚持:

  • 高风险动作要复核身份
  • 只能动自己的凭据
  • 凭据集合变化后要刷新 session 信任态

这三点一起,才构成真正可上线的 portal self-service passkey。

实战里最容易踩的 4 个误区

误区 1:把已登录态当成高信任态

Portal 用户已经登录,不代表可以直接增删认证器。共享设备、被盗 cookie、旁路登录都可能让“已登录态”不再可靠。

误区 2:只做前端过滤,不做后端所有权校验

页面上只展示自己的 key 不够,后端必须检查 create_uid,否则直接改请求仍可能越权。

误区 3:新增 / 删除凭据后不刷新 session token

否则你以为系统看到了“认证面已变化”,其实旧 session 还沿用旧快照。

误区 4:把 portal passkey 当成纯前端功能

真正难点不在按钮和弹窗,而在 challenge、identity check、对象权限和 session invalidation 是不是打通。

我会怎么向业务团队解释这套设计

如果你要用一句最通俗的话解释给非技术同事听,我会这么说:

Portal Passkey 不是让用户“更方便登录”这么简单,而是让用户能安全地自己管理长期登录凭据,同时确保错的人不能趁机把账号据为己有。

所以它的价值既是体验,也是治理;既是无密码趋势,也是账号接管防线。

结语

看完这套源码后,一个判断会变得很清楚:auth_passkey_portal 真正升级的不是页面,而是信任模型。

它把门户用户从“只能被动使用登录方式”推进到“可以自助治理认证资产”,但每一步都用 check_identity、对象所有权和 session token 重算把风险重新圈住。

这也是 Odoo 平台层一贯的风格:

  • UI 可以轻
  • 交互可以顺
  • 但安全边界绝不靠“大家应该会正常使用”来赌

这,才是 Portal Passkey 值得写一篇文章的原因。ey 值得写一篇文章的原因。

DISCUSSION

评论区

想参与讨论?先 登录 再发表评论。
还没有评论,你可以成为第一个留言的人。