mcpField
C
ce-auth

ce-auth

github.com/commercengine开发035 次安装9 周前更新
代码仓库

关于 ce-auth

ce-auth 介绍 Commerce Engine SDK 的身份验证与用户管理模式,面向店面开发者,涵盖匿名会话、OTP 或密码登录、账户操作与退出,并区分公开读取和会话流程。

主要功能

  1. 01启动匿名会话
  2. 02支持邮箱、电话和 WhatsApp OTP
  3. 03密码登录与注册
  4. 04重置密码和刷新令牌
  5. 05管理用户资料并退出登录

适用场景

  1. 01为店面添加登录功能
  2. 02支持无密码登录和账户创建
  3. 03实现账户页面与资料更新
  4. 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()启动实时会话
邮箱 OTPsdk.auth.loginWithEmail() -> sdk.auth.verifyOtp()无密码邮箱登录
手机 OTPsdk.auth.loginWithPhone() -> sdk.auth.verifyOtp()无密码手机登录
WhatsApp OTPsdk.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 Checkout
  • orders/ - 已登录用户的订单流程
  • ssr-patterns/ - 用于身份验证变更的服务器操作/函数(Next.js、TanStack Start)

文档

评论

支持 Markdown