Logto MFA 可信设备:可配置策略、设备生命周期管理与 Webhook 事件

发布时间:2026/9/14 20:45:30

Logto MFA 可信设备:可配置策略、设备生命周期管理与 Webhook 事件 Logto MFA 可信设备可配置策略、设备生命周期管理与 Webhook 事件【免费下载链接】logto‍ Authentication and authorization infrastructure for SaaS and AI apps, built on OIDC and OAuth 2.1 with multi-tenancy, SSO, and RBAC.项目地址: https://gitcode.com/GitHub_Trending/lo/logto本文基于 Logto 仓库中的 changeset 变更记录 shiny-mugs-hope.md 展开完整讲解该变更所引入的「MFA 可信设备Trusted Devices」能力租户级可配置策略与组织级限制的生效规则、用户在登录/注册流程末尾通过专属页面选择信任设备后跳过重复 MFA 的完整链路以及通过 Console、Account Center、Management API、Account API 四个入口管理设备与订阅设备生命周期 Webhook 的实操方式。读完本文你可以理解该功能的数据库模型、Cookie 凭据设计、策略解析逻辑与各 API 的调用方式。变更概览一次横跨五个包的 minor 变更该 changeset 声明本次功能属于 minor 版本升级涉及以下五个包logto/experience登录/注册体验前端新增可信设备选择页面logto/accountAccount Center 前端新增可信设备管理界面logto/console管理后台新增租户级策略与组织级限制的配置入口logto/schemas共享 Schema 层新增trusted_devices表结构与策略类型定义logto/core服务端核心新增策略解析库、凭据库、Experience/Account/Management 路由与 Hook 事件。变更描述的核心承诺是配置租户级可信设备策略与组织级限制用户在完成 MFA 后可在登录或注册流程末尾的专属页面选择是否信任当前设备从而在该浏览器上跳过重复 MFA设备可通过 Console、Account Center、Management API、Account API 管理并可订阅设备生命周期 Webhook。数据模型trusted_devices 表该功能的持久化基础是新增的trusted_devices表定义在 trusted_devices.sql/** A revocable server-side credential that can fulfill sign-in MFA for a user. */ create table trusted_devices ( tenant_id varchar(21) not null references tenants (id) on update cascade on delete cascade, id varchar(21) not null, user_id varchar(12) not null references users (id) on update cascade on delete cascade, secret_hash bytea /* use BufferLike */ not null, user_agent text, ip text, country varchar(16), city text, created_at timestamptz not null default(now()), last_used_at timestamptz not null default(now()), expires_at timestamptz not null, primary key (id) ); create index trusted_devices__tenant_user_expires_at on trusted_devices (tenant_id, user_id, expires_at); create index trusted_devices__tenant_expires_at on trusted_devices (tenant_id, expires_at);从表结构可以看到几个关键设计决策只存密钥哈希不存明文secret_hash是bytea类型服务端凭据的明文密钥只写入浏览器 Cookie数据库仅保留其 SHA-256 哈希泄露数据库无法直接还原可用凭据多租户隔离tenant_id必填且级联删除两条索引分别覆盖「按用户查询活跃设备」和「按租户批量清理过期记录」两种访问路径设备画像字段user_agent、ip、country、city均为可空文本用于在 Console 和 Account Center 中展示设备来源方便管理员判断陌生设备。对外返回时该表并非整体暴露。trusted-device.ts 中定义了两个响应模型trustedDeviceResponseGuardManagement API 使用的公开元数据包含id、userAgent、country、city、createdAt、lastUsedAt、expiresAtaccountTrustedDeviceResponseGuardAccount API 在其基础上扩展isCurrent布尔字段标记「当前浏览器是否为受信任设备」。secretHash、ip、userId等敏感或内部字段均不出现在响应中。策略层租户默认策略 组织级限制租户级策略sign-in experience 中的 trustedDevice 字段租户级策略挂载在 Sign-in Experience 配置上类型定义与默认值位于 sign-in-experience.tsexport const defaultTrustedDevicePolicy Object.freeze({ enabled: false, durationDays: 30, }) satisfies RequiredTrustedDevicePolicy; export const trustedDevicePolicyGuard z.object({ enabled: z.boolean().optional(), durationDays: z.number().int().min(1).max(365).optional(), }) satisfies ToZodObjectTrustedDevicePolicy;参数说明参数类型取值范围默认值含义enabledboolean可省略true / falsefalse是否为该租户启用可信设备能力durationDaysnumber可省略1 ~ 365 的整数30信任凭据的有效期天即默认情况下功能处于关闭状态租户需在 Console 的 MFA 配置页对应前端实现 TrustedDeviceSettings.tsx显式开启并设置时长。组织级限制hasDisallowedOrganization策略并非单纯的全租户开关。组织Organization维度引入了isTrustedDeviceAllowed标志用户若隶属于任一「不允许可信设备」的组织其可信设备能力将被强制关闭。这一判定在 trusted-device-policy.ts 中完成export const resolveEffectiveTrustedDevicePolicy ( policy: TrustedDevicePolicy, hasDisallowedOrganization: boolean ): EffectiveTrustedDevicePolicy ({ enabled: (policy.enabled ?? defaultTrustedDevicePolicy.enabled) !hasDisallowedOrganization, durationDays: policy.durationDays ?? defaultTrustedDevicePolicy.durationDays, });生效策略Effective Policy的解析规则非常直白读取默认 Sign-in Experience 的trustedDevice配置并行查询用户是否属于任何isTrustedDeviceAllowed false的组织hasUserDisallowedTrustedDeviceOrganization见 user-relations.ts最终enabled 租户策略启用 未被任何组织禁用durationDays缺失时回落到默认值 30 天。组织级开关的前端入口在 Console 的组织设置页TrustedDeviceSettings.tsx。这意味着即使租户全局开启敏感业务线所属组织仍可按需禁用实现「租户放行、组织收紧」的两级控制。凭据体系从密钥生成到 Cookie 校验可信设备的核心实现是 trusted-device.ts 中的createTrustedDeviceLibrary它管理「服务端凭据 浏览器 Cookie」这对组合。密钥生成与哈希const trustedDeviceSecretByteLength 32; const trustedDeviceSecretHashAlgorithm sha256; export const generateTrustedDeviceSecret () randomBytes(trustedDeviceSecretByteLength).toString(base64url); export const hashTrustedDeviceSecret (secret: string) hashTrustedDeviceSecretBytes(Buffer.from(secret, base64url));密钥由node:crypto的randomBytes(32)生成256 位随机数base64url 编码后存入 Cookie数据库中仅存sha256(密钥字节)校验时使用timingSafeEqual做恒定时间比较verifyTrustedDeviceSecret避免时序侧信道。Cookie 命名与属性Cookie 名称按「租户 用户」做 SHA-256 哈希命名避免在 Cookie 名中泄露身份信息const trustedDeviceCookiePrefix logto-trusted-device-; const trustedDeviceOptOutCookiePrefix logto-device-trust-opt-out-; const getUserScopedCookieName (prefix, tenantId, userId, isProduction) { const subjectHash createHash(sha256) .update(${tenantId}:${userId}) .digest(base64url); const name ${prefix}${subjectHash}; return isProduction ? __Host-${name} : name; };生产环境下 Cookie 带__Host-前缀浏览器强制其必须Secure、Path/写入时统一设置httpOnly: true、sameSite: lax、secure: isProductionJS 无法读取该凭据。凭据本身序列化为id.secret两段式格式serializeTrustedDeviceCredential解析端parseTrustedDeviceCredential严格校验 id 格式/^[\da-z]$/、secret 的 base64url 规范形态与恰好 32 字节长度任何非法格式都会触发clearCredential清 Cookie 并回落到正常 MFA 流程——凭据损坏只会让用户重新走一次 MFA不会造成安全误判。写入竞态与过期清理createCredential中有一处值得注意的并发设计先以insertIfNotExists尝试入库只有赢得插入竞争的那次请求才会把与自己密钥匹配的凭据写入 Cookie。源码注释明确说明这是为了防止「两次相同创建意图的请求同时提交时后到的响应用其随机凭据覆盖了数据库中并不存在对应记录的 Cookie」。此外cleanupExpired以 5 分钟冷却trustedDeviceCleanupCooldown异步清理租户内过期记录清理失败会重置冷却时间允许下一次机会重试。登录/注册流程中的可信设备链路服务端流程编排类TrustedDevicetrusted-device.ts负责协调「持久化的选择决策」与「请求内的凭据生命周期」嵌入 Sign-In 与 Sign-Up 交互experience-interaction.ts完整链路如下1. MFA 验证阶段优先校验可信设备tryVerifyMfa(userId)在 MFA 校验入口被调用若用户已有可信设备 Cookie 且生效策略enabled则直接validateCredential校验 Cookie 中的凭据校验成功即视为完成 MFA用户无感知地跳过重复验证。校验通过后记录#validatedDeviceId供提交后更新lastUsedAt。2. 提交阶段建议信任当前设备当用户通过正常方式完成 MFA 后assertOptInDecision判断是否需要在流程末尾展示「信任此设备」页面忘记密码ForgotPassword流程不参与可信设备用户已做出选择、或存在「拒绝信任」的 opt-out Cookie此前选过「不信任」且仍在策略时长内则不再询问必须已有合格 MFA 证明hasEligibleMfaProof生效策略enabled为真时抛出422 session.trusted_device_suggest_opt_in错误并携带durationDays供前端渲染提示文案。这是典型的「用交互错误码驱动流程跳转」模式前端捕获该错误码后跳转至专属页面。3. 专属选择页面/trusted-device前端实现位于 experience 包的 TrustedDevice/index.tsx页面通过路由 state 携带durationDays与交互事件类型渲染「信任此设备」/「不信任」两个决策按钮调用setTrustedDeviceOptInDecision(trusted: boolean)提交决策成功后按返回的redirectTo跳转回原流程。服务端setOptInDecision对两种决策的处理不信任记录trusted: false的决策并在策略启用时写入 opt-out CookiewriteOptOut时长等于策略durationDays——在信任期长度内不再重复询问该用户该浏览器信任要求已通过 MFA否则抛403 session.mfa.require_mfa_verification策略启用时生成/沿用deviceId存入交互存储等待提交阶段落库。4. 提交阶段创建或使用finalize在交互提交时收尾分两种情况使用路径本次 MFA 由可信设备凭据完成时更新该设备的userAgent/ip/country/city元数据即lastUsedAt语义仅对 Sign-In 事件追加TrustedDevice.Used审计日志且日志 id 由sha256(TrustedDevice.Used:tenantId:interactionId)截断生成、作为幂等键同一交互不会重复记录创建路径用户选择信任且具备合格 MFA 证明时调用createCredential落库并写 Cookie同时追加TrustedDevice.Created审计日志与 Hook 上下文。所有审计与 Hook 载荷都刻意设置includeRequestIp: false源码注释Trusted-device lifecycle payloads intentionally exclude the request IP生命周期事件不附带请求 IP收敛敏感面。管理入口Console、Account Center、Management API、Account APIchangeset 承诺的四个管理入口在仓库中均有对应实现。Management API管理员/服务端视角实现于 admin-user/trusted-device.tsGET /users/:userId/trusted-devices先校验用户存在不存在返回 404返回该用户全部活跃设备的TrustedDeviceResponse数组id、userAgent、country、city、createdAt、lastUsedAt、expiresAtDELETE /users/:userId/trusted-devices/:trustedDeviceId通过deleteByIdAndUserId删除限定userId维度防止跨用户越权删除返回 204设备不存在返回 404。删除经由 Hook 上下文触发TrustedDevice.DeletedWebhook 事件。Account API用户自助视角实现于 account/trusted-device.tsGET {accountApiPrefix}/trusted-devices三重前置校验——身份已验证identityVerified否则 401、Account Center 中trustedDevice字段为Edit或ReadOnly否则报account_center.field_not_enabled、令牌具备UserScope.TrustedDevicesscope否则 401。返回AccountTrustedDeviceResponse数组其中isCurrent由当前请求 Cookie 校验结果比对得出前端据此高亮「当前设备」DELETE {accountApiPrefix}/trusted-devices/:trustedDeviceId用户自助撤销设备。Account Center 的字段开关定义在 account-centers.tstrustedDevice: AccountCenterControlValue管理员可控制用户在 Account Center 中是编辑、只读还是完全隐藏该能力。前端管理界面Console 中查看用户设备UserTrustedDevices/index.tsx用户详情页与租户级策略开关Mfa 配置页Account Center 中的设备管理页位于 account 包的 Device 目录展示设备列表、当前设备标记与撤销操作组织级开关位于 OrganizationDetails/Settings/TrustedDeviceSettings.tsx。Webhook设备生命周期事件设备生命周期通过 Logto Hooks 机制对外暴露事件类型见 hook 测试 与 libraries/trusted-device.ts 中的appendDataHookContext调用事件触发时机载荷TrustedDevice.Created用户在可信设备页面选择信任并成功落库{ id, userId, expiresAt }TrustedDevice.Deleted经 Management API / Account API / Console 撤销设备{ id, userId, expiresAt }两个事件的载荷均由getTrustedDeviceEventData构造只包含设备 id、所属用户与过期时间且显式不携带请求 IP。订阅方通过 Console 的 Hooks 配置可据此在设备被撤销时联动清理自己侧的会话或会话令牌实现「设备撤销即会话失效」的安全闭环。TrustedDevice.Used目前仅作为内部审计日志类型写入服务日志见 log.ts 的类型引用不在 changeset 描述的 Webhook 事件范围内。安全设计小结结合源码实现这套可信设备机制的安全边界可以归纳为服务端可撤销凭据表头注释即定义为 A revocable server-side credential that can fulfill sign-in MFA for a user撤销删库记录即刻使 Cookie 失效validateCredential会清 Cookie 并回退 MFA数据库只存哈希明文密钥仅存在于 HttpOnly Cookie生产环境强制Secure__Host-前缀策略双闸门租户策略 组织级限制取交集任一禁用即整体禁用凭据校验前会先校验生效策略策略被关时旧 Cookie 同样失效范围限定仅 Sign-In / Sign-Up 流程参与忘记密码流程明确排除竞态安全凭据写入以数据库插入成功为前置条件避免 Cookie 与库记录不一致事件收敛Webhook 载荷最小化id/userId/expiresAt不含 IP。延伸阅读变更声明.changeset/shiny-mugs-hope.md表结构trusted_devices.sql策略解析trusted-device-policy.ts凭据库trusted-device.ts流程编排experience/classes/trusted-device.tsManagement API 路由admin-user/trusted-device.tsAccount API 路由account/trusted-device.ts前端选择页TrustedDevice/index.tsx相关测试libraries/trusted-device.test.ts、experience/classes/trusted-device.test.ts、account/trusted-device.test.ts【免费下载链接】logto‍ Authentication and authorization infrastructure for SaaS and AI apps, built on OIDC and OAuth 2.1 with multi-tenancy, SSO, and RBAC.项目地址: https://gitcode.com/GitHub_Trending/lo/logto创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/14 20:45:30

FPGA/DSP供电设计:噪声与瞬态响应的硬核解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/14 20:45:30

微信小程序app.json/app.js/app.wxss协同机制解析

简介:本资源是一套完整可运行的微信小程序实战项目源码,专为前端开发者及小程序入门学习者设计,聚焦一元夺宝类电商场景,解决从零搭建高互动性轻量级商城的核心开发需求。资源包共34个文件,包含21张界面截图&#xff0…

2026/9/14 21:00:31

Matlab/Simulink柴油发电机微电网仿真建模实践

1. 柴油发电机仿真系统概述柴油发电机作为微电网系统中的关键备用电源,其动态特性直接影响整个系统的稳定性。在Matlab/Simulink环境下搭建柴油发电机仿真模型,能够有效评估其在并网/孤岛模式下的运行性能。典型的微电网架构包含光伏阵列(PV&…

2026/9/14 21:00:31

基于Django与微信小程序的智能制造业ERP系统开发实践

1. 项目背景与核心价值制造业ERP系统作为企业资源管理的核心平台,其移动化转型已成为行业刚需。这个基于Django框架的智能制造业ERP解决方案,通过微信小程序实现移动端接入,解决了传统ERP系统在以下场景的痛点:车间主任需要实时审…

2026/9/14 21:00:31

海尔Horizon冰箱技术解析与市场战略

1. 项目概述:海尔Horizon冰箱英国首发的战略意义2023年海尔在英国市场推出的Horizon系列冰箱,是其全球化战略中的关键落子。作为定位高端的旗舰产品线,Horizon的命名本身就蕴含着三重战略意图:首先"地平线"象征技术边界…

2026/9/14 21:00:31

Vue3双向绑定组件开发:多变量与修饰符实战

1. Vue3双向绑定组件的核心需求解析双向绑定是Vue框架最标志性的特性之一,在Vue3中通过组合式API得到了进一步增强。当我们谈到"支持多绑定变量和修饰符的双向绑定组件"时,实际上是在解决以下三个核心问题:多变量同步:传…

2026/9/14 21:00:31

IntelliJ IDEA社区版:开源轻量IDE的调优与ARM边缘设备实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/14 20:55:30

Vue3双向绑定进阶:defineModel多变量与修饰符实战

1. Vue3双向绑定组件的核心价值与挑战双向绑定一直是Vue框架最标志性的特性之一。在Vue3中,随着Composition API的成熟和defineModel宏的引入,双向绑定的实现方式变得更加优雅和强大。但在实际开发中,我们经常会遇到需要处理多个绑定变量和自…

2026/9/14 2:17:50

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/14 0:03:22

KCF目标跟踪算法与OTB工程实现:毕业设计实战解析

简介:这是一份基于KCF核相关滤波算法、融合尺度池与抗遮挡处理的目标检测跟踪MATLAB完整源码,主要面向计算机相关专业准备毕业设计、课程设计或期末大作业的学生,也适合需要项目实战练习的初学者。源码在OTB数据集上完成验证,能够…

2026/9/14 0:03:22

语音情感识别实战:Keras实现LSTM、CNN、SVM与MLP多模型对比

简介:面向语音情感识别入门与进阶开发者,这份基于Keras的项目源码完整实现了LSTM、CNN、SVM、MLP四种模型,兼容Python3.8与Keras/TensorFlow2环境。压缩包内含49个文件,大小约70.31MB,主体包括Python脚本、yaml/json配…

2026/9/14 11:59:31

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/14 13:53:59

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/14 11:22:57

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码