关于 ce-auth
ce-auth 介绍 Commerce Engine SDK 的身份验证与用户管理模式,面向店面开发者,涵盖匿名会话、OTP 或密码登录、账户操作与退出,并区分公开读取和会话流程。
主要功能
- 01启动匿名会话
- 02支持邮箱、电话和 WhatsApp OTP
- 03密码登录与注册
- 04重置密码和刷新令牌
- 05管理用户资料并退出登录
适用场景
- 01为店面添加登录功能
- 02支持无密码登录和账户创建
- 03实现账户页面与资料更新
- 04处理购物车和结账的会话访问
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ commercengine/ skills --skill ce-auth安装后在 Claude Code 中输入/ce-auth确认已加载。
附带文件.claude-plugin/plugin.json.cursor-plugin/plugin.json
详细介绍
LLM 文档请求头:所有对
https://llm-docs.commercengine.io的请求必须包含Accept: text/markdown请求头(或在 URL 路径末尾追加.md)。否则,响应将返回 HTML,而不是可解析的 Markdown。
身份验证与用户管理
前提条件:必须已初始化 SDK。如果尚未完成,请参阅
setup/。
何时直接实现身份验证
如果使用 Hosted Checkout,登录和注册通常在结账抽屉内处理。只有当店面需要在结账之外呈现已登录状态时,才构建自定义身份验证界面,例如:
- 账户页面
- 已保存的地址
- 订单历史记录
- 忠诚度或钱包页面
- 持续显示的已登录页眉状态
当前的概念模型
- 公开的商品和类别读取可使用
public(),不需要匿名身份验证。 - 实时购物车、账户和结账流程应使用会话客户端。
- 在托管会话模式下,SDK 可在首次需要令牌的请求中自动初始化匿名身份验证。
- 如果需要提前建立匿名会话,请在启动时调用一次
sdk.ensureAccessToken()。
快速参考
| 身份验证方法 | 端点 | 使用场景 |
|---|---|---|
| 匿名初始化 | sdk.ensureAccessToken() 或 sdk.auth.getAnonymousToken() | 启动实时会话 |
| 邮箱 OTP | sdk.auth.loginWithEmail() -> sdk.auth.verifyOtp() | 无密码邮箱登录 |
| 手机 OTP | sdk.auth.loginWithPhone() -> sdk.auth.verifyOtp() | 无密码手机登录 |
| WhatsApp OTP | sdk.auth.loginWithWhatsApp() -> sdk.auth.verifyOtp() | 无密码 WhatsApp 登录 |
| 密码登录 | sdk.auth.loginWithPassword() | 传统登录 |
| 密码注册 | sdk.auth.registerWithPassword() -> OTP verification | 密码注册 |
| 忘记密码 | sdk.auth.forgotPassword() -> sdk.auth.resetPassword() | 使用 OTP 重置密码 |
| 刷新令牌 | sdk.auth.refreshToken() | 续期过期的访问令牌 |
决策树
User Request
│
├─ Public catalog-only page
│ └─ No auth bootstrap needed; use public()
│
├─ New visitor starting a live session
│ └─ sdk.ensureAccessToken()
│
├─ "Login" / "Sign in"
│ ├─ Passwordless → loginWithEmail/Phone/WhatsApp() → verifyOtp()
│ └─ Password → loginWithPassword()
│
├─ "Register"
│ └─ registerWithPassword() / registerWithPhonePassword() → verifyOtp()
│
├─ "Forgot password"
│ └─ forgotPassword() → resetPassword()
│
├─ "Account" / "Profile"
│ └─ getUserDetails() / updateUserDetails()
│
└─ "Token expired" / 401
└─ refreshToken() or rely on managed session refresh
用户状态
| 状态 | 创建方式 | 功能 |
|---|---|---|
| 公开 | 仅使用 public() 访问器 | 公开目录/店面/辅助工具读取 |
| 匿名会话 | sdk.ensureAccessToken() 或 /auth/anonymous | 购物车、结账、分析、会话连续性 |
| 已登录会话 | OTP 验证、密码登录或完成密码重置 | 所有匿名会话功能,以及账户、订单、地址和忠诚度功能 |
用户 ID 与客户 ID
对于大多数店铺,user_id 和 customer_id 是相同的值——一个用户对应一个客户。在 B2B 店面中,一个客户可以有多个用户(例如,拥有多名员工的公司账户)。
SDK 提供了获取两者的辅助方法:
const userId = await sdk.getUserId();
const customerId = await sdk.getCustomerId();
大多数需要用户 ID 或客户 ID 的 SDK 方法都提供无参数重载,可从当前会话自动解析。例如,sdk.cart.getUserCart()(无参数)会自动获取已登录用户的购物车。只有在代表其他用户操作时(管理员场景),才显式传入 ID。
关键模式
启动实时匿名会话
const sdk = storefront.session();
await sdk.ensureAccessToken();
如果需要提前初始化,请在启动时调用一次。普通的、支持会话的购物车、订单或客户调用之前,不要重复调用。
OTP 登录流程(邮箱)
const { data, error } = await sdk.auth.loginWithEmail({
email: "[email protected]",
register_if_not_exists: true,
});
if (error) throw error;
const { otp_token, otp_action } = data!;
const { error: verifyError } = await sdk.auth.verifyOtp({
otp: "123456",
otp_token,
otp_action,
});
if (verifyError) throw verifyError;
密码登录
const { data, error } = await sdk.auth.loginWithPassword({
email: "[email protected]",
password: "securepassword",
});
if (error) throw error;
密码注册
最新契约中,密码注册以 OTP 验证为先。
const { data, error } = await sdk.auth.registerWithPassword({
email: "[email protected]",
password: "securepassword",
confirm_password: "securepassword",
});
if (error) throw error;
await sdk.auth.verifyOtp({
otp: "123456",
otp_token: data!.otp_token,
otp_action: data!.otp_action,
});
忘记密码
const { data, error } = await sdk.auth.forgotPassword({
email: "[email protected]",
});
if (error) throw error;
await sdk.auth.resetPassword({
otp: "123456",
otp_token: data!.otp_token,
new_password: "newPass123",
confirm_password: "newPass123",
});
用户资料
身份验证客户端方法需要显式传入 ID(没有无参数重载)。使用 sdk.getUserId() 获取当前用户的 ID:
const userId = await sdk.getUserId();
const { data: userData } = await sdk.auth.getUserDetails({ id: userId! });
await sdk.auth.updateUserDetails({ id: userId! }, {
first_name: "Jane",
last_name: "Doe",
});
关键功能:register_if_not_exists
在登录端点设置 register_if_not_exists: true,即可省去单独的登录和注册入口。如果用户不存在,Commerce Engine 会创建账户并继续 OTP 流程。
这也是结账身份验证的推荐方式——没有单独的“访客结账”流程。用户提供邮箱或手机号,通过 OTP 验证后,如有需要,系统会创建账户。这种最简便的方式可确保地址经过验证,并将订单归属到相应用户。Hosted Checkout 会自动处理整个流程。
登出
SDK 提供 sdk.auth.logout(),可用于自定义登出按钮:
const { data, error } = await sdk.auth.logout();
logout() 不会清除令牌,而是返回权限降低后的新令牌。会话仍保持完整连续性(购物车和分析记录均不变),但用户不再处于已登录状态。SDK 的 onTokensUpdated 回调会随新令牌触发;使用 authMode: "provided" 时,与 Hosted Checkout 的双向同步会自动传递这些令牌,无需手动清除令牌或调用 updateTokens("", "")。
常见问题
| 级别 | 问题 | 解决方案 |
|---|---|---|
| CRITICAL | 使用 public() 执行身份验证或账户操作 | 使用会话客户端 |
| CRITICAL | 认为每个页面都需要匿名身份验证 | 公开读取操作不需要;只有实时会话流程需要 |
| HIGH | 默认构建独立的登录和注册流程 | 在适用场景中优先使用 register_if_not_exists: true |
| HIGH | 在步骤之间忘记传递 otp_token 和 otp_action | 持久化保存两者,并传给 verifyOtp() |
| HIGH | 以不安全的方式存储令牌,或使用与运行环境不匹配的存储方式 | 根据环境使用托管会话存储 |
| MEDIUM | 忽略 { data, error } | 使用 data 前始终检查 error |
另请参阅
setup/- SDK 安装和会话存储cart-checkout/- 结账流程和 Hosted Checkoutorders/- 已登录用户的订单流程ssr-patterns/- 用于身份验证变更的服务器操作/函数(Next.js、TanStack Start)