已登录改密码
auth.settings 命名空间提供已登录用户的 step-up 改密流程(邮件验证码 → 改密)。它与 auth.reset 是两个正交场景的 namespace,详见下文「与 auth.reset 的差异」。
这两个 namespace 用错会出大问题
- 已登录用户改密码用
auth.reset→ 改完原 session 失效,用户被踢出去重新登录(v2 reset 设计意图就是「未登录恢复」) - 未登录用户恢复密码用
auth.settings→sendVerifyCode在createBrowserLoginFlow({ refresh: true })时就抛 401,跑不动
判据:dialog 入口在哪。登录页的「忘记密码」链接 → auth.reset;用户中心 / 设置页里的改密 dialog → auth.settings。
三段流程
auth.settings.sendVerifyCode({ email })— 创建 ory login flow withrefresh=true+ method=code,下发邮件auth.settings.verifyCode({ code })— 提交验证码完成 refresh login flow,当前 session 被标记为 privilegedauth.settings.updatePassword({ newPassword })— 在 privileged session 内走 settings flow 改密码,session 保持不变
底层依次走 ory createBrowserLoginFlow({ refresh: true }) → updateLoginFlow(method: 'code', identifier) → updateLoginFlow(method: 'code', code, identifier) → createBrowserSettingsFlow → updateSettingsFlow(method: 'password', password)。SDK 内部维护「当前活跃的 refresh login flow」串起前两段。
最短链路
ts
import { TripoAuth, TripoAuthError } from '@tripo3d/auth';
const auth = new TripoAuth({
basePath: 'https://auth.tripo3d.ai',
});
// 前置:用户已登录(auth.token.peek() 非空)
// 1. 给当前用户的注册邮箱发 step-up 验证码
await auth.settings.sendVerifyCode({ email: 'user@example.com' });
// 2. 用户拿到邮件验证码 → 提交完成 session 提权
await auth.settings.verifyCode({ code: '123456' });
// 3. privileged session 内改密码;session 保持,业务继续走
try {
await auth.settings.updatePassword({ newPassword: 'new-strong-password' });
} catch (err) {
if (err instanceof TripoAuthError && err.name === 'PRIVILEGED_SESSION_EXPIRED') {
// 用户在 verifyCode 与 updatePassword 之间停太久(ory privileged_session_max_age 默认 15 min)
// → 业务侧引导回 sendVerifyCode 重发验证码
}
}与 auth.reset 的差异
| 维度 | auth.reset.* | auth.settings.* |
|---|---|---|
| 起点 session | 无(忘记密码场景) | 有(已登录改密码场景) |
| 底层 ory flow 链 | recovery → settings,拆 3 段(sendCode·verifyCode·submitNewPassword) | login(refresh=true) → settings,拆 3 段 |
| 公开方法数 | 3(sendCode / verifyCode / submitNewPassword) | 3(sendVerifyCode / verifyCode / updatePassword) |
| 改完 session | 替换/失效(业务方常引导重登) | 保持原 session |
| 是否写登录信号 cookie | 否 | 否 |
| 典型 UI | 两屏:① email + 验证码 → ② 新密码 | 两屏:① 验证码 → ② 新密码 |
| 中间态 sharp edge | 有:verifyCode 后的 privileged session 过期窗口 | 有:privileged session 默认 15 min 过期窗口 |
Vue 接入示例(两屏 UX,与产品交互对齐)
vue
<!-- Stage 1: 邮箱验证 -->
<script setup lang="ts">
const { $auth } = useNuxtApp();
const emit = defineEmits<{ (e: 'switchState', s: 'ResetPassword'): void }>();
const userStore = useUserStore();
const code = ref('');
const sendCode = (target: { email: string }) => $auth.settings.sendVerifyCode(target);
const onSubmit = async () => {
try {
await $auth.settings.verifyCode({ code: code.value });
emit('switchState', 'ResetPassword');
} catch (err) {
// FLOW(验证码错 / 频控 / 过期):toast 提示,留在本页让用户重输或重发
handleAuthError(err);
}
};
</script>
<template>
<DialogPersonalResetPasswordFieldEmail
disabled
:model-value="userStore.detail.email"
/>
<DialogPersonalResetPasswordFieldCode
v-model="code"
:send-code="sendCode"
/>
<Button @click="onSubmit">下一步</Button>
</template>vue
<!-- Stage 2: 新密码 -->
<script setup lang="ts">
const { $auth } = useNuxtApp();
const emit = defineEmits<{ (e: 'switchState', s: 'ValidEmail'): void }>();
const password = ref('');
const onSubmit = async () => {
try {
await $auth.settings.updatePassword({ newPassword: password.value });
toast.success($t('phrase.password_reset_successful'));
// session 没变,业务继续走
} catch (err) {
if (err instanceof TripoAuthError && err.name === 'PRIVILEGED_SESSION_EXPIRED') {
// 提权过期:toast + 回上一步重发验证码
toast.error($t('phrase.session_expired_resend_code'));
emit('switchState', 'ValidEmail');
return;
}
handleAuthError(err);
}
};
</script>API 参考
| 方法 | 签名 | 说明 |
|---|---|---|
auth.settings.sendVerifyCode | (args: { email }) => Promise<void> | 创建 ory login flow with refresh=true + method=code;触发邮件下发;flow id + csrf + identifier 写入实例级 holder |
auth.settings.verifyCode | (args: { code }) => Promise<void> | 在 refresh login flow 上提交 code → 当前 session 被标记为 privileged;成功后清 holder |
auth.settings.updatePassword | (args: { newPassword }) => Promise<void> | privileged session 内走 settings flow 改密码;session 保持;不写登录信号 cookie |
常见错误
完整错误分类见 错误处理:
FLOW— 验证码错(verifyCode)/ 新密码强度不达标(updatePassword 被 ory 拒);message 直接 toastNETWORK— fetch 抛错 / HTTP 5xxVALIDATION—verifyCode在没先sendVerifyCode的情况下被调用PRIVILEGED_SESSION_EXPIRED—updatePassword时当前 session 未提权或提权已过期(oryprivileged_session_max_age,默认 15 min)。业务侧应 toast 提示 + 把 UI 切回 sendVerifyCode 一步INTERNAL— flow ui 节点取不到 csrf_token(理论上 ory 不应出现)
下一步
- 密码重置 —— 未登录恢复(
auth.reset.*) - 错误处理 ——
TripoAuthError完整分类与 catch 模板 - Playground