跳到主要内容

登录认证

提示

新登录体系下,确保一个环境对应一个 tcb 实例(避免多次初始化相同环境的 tcb 实例)

App.auth()#

接口描述#

返回 Auth 对象

签名:auth(): Auth

warning

@cloudbase/js-sdk@2.x 版本将只支持 local 方式(Web 端在显式退出登录之前 30 天保留身份验证状态)存储身份状态。(原 1.x 版本的 sessionnone 模式不再支持)

示例代码#

import cloudbase from "@cloudbase/js-sdk"
const app = cloudbase.init({  env: "xxxx-yyy",  clientId: "xxxx"})
const auth = app.auth()

注册/登录/登出相关#

Auth.signUp#

接口描述#

接口功能:注册用户,目前支持手机号验证码注册,邮箱验证码注册。

接口声明:signUp(params: SignUpRequest): Promise<LoginState>

SignUpRequest#
字段类型必填说明
phone_numberstring注册所用手机号,phone_number 与 email 必须任选其一使用
emailstring注册所用邮箱 ,phone_number 与 email 必须任选其一使用
verification_codestring验证码
verification_tokenstring验证码 token
provider_tokenstring第三方 provider token
passwordstring密码
namestring用户名
genderstring性别
picturestring头像
localestring地址

示例代码#

const app = cloudbase.init({  env: "xxxx-yyy",  clientId: "xxxxx"})
const auth = app.auth()
// 例:手机号验证码注册
// 1. 发送手机验证码const phoneNumber = "+86 13800000000"const verification = await auth.getVerification({  phone_number: phoneNumber})
/*// 若使用邮箱验证,第一步代码改为const email = "test@example.com"const verification = await auth.getVerification({  email: email});*/
// 2. 验证码验证 TODO: 解释// 调用发送短信接口后,手机将会收到云开发的短信验证码。用户填入短信验证码,可以调用下面的接口进行验证,例如:验证码是:000000
const verificationCode = "000000"// 验证验证码的正确性const verificationTokenRes = await auth.verify({  verification_id: verification.verification_id,  verification_code: verificationCode})
// 3. 注册// 如果该用户已经存,则登录if (verification.is_user) {  await auth.signIn({    username: phoneNumber,    verification_token: verificationTokenRes.verification_token  })} else {  // 否则,则注册新用户,注册新用户时,可以设置密码,用户名  // 备注:signUp 成功后,会自动登录  await auth.signUp({    phone_number: phoneNumber,    verification_code: verificationCode,    verification_token: verificationTokenRes.verification_token,    // 可选,设置昵称    name: "手机用户",    // 可选,设置密码    password: "password",    // 可选,设置登录用户名    username: "username"  })}

Auth.signIn#

接口描述#

接口功能:登录用户,目前支持手机号,邮箱,用户名密码登录。

接口声明:signIn(params: SignInRequest): Promise<LoginState>

SignInRequest#
字段类型必填说明
usernamestring用户手机号,邮箱或自定义用户名
passwordstring用户密码 ,password 与 verification_token 必须任选其一
verification_tokenstring验证码 token ,password 与 verification_token 必须任选其一

示例代码#

const app = cloudbase.init({  env: "xxxx-yyy",  clientId: "xxxxx"})
const auth = app.auth()
// 已完成注册// 例:手机号登录const phoneNumber = "+86 13800000000"
await auth.signIn({  username: phoneNumber,  password: "your password"})
// 例:邮箱登录const email = "test@example.com"
await auth.signIn({  username: email,  password: "your password"})
// 例:用户名登录const username = "myname"await auth.signIn({  username,  password: "your password"})

Auth.signOut()#

接口描述#

登出云开发

签名:signOut(): Promise<void>

示例代码#

const app = cloudbase.init({  env: "xxxx-yyy"})
const auth = app.auth()
await auth.signOut()

Auth.signInAnonymously()#

接口描述#

匿名登录

接口声明 signInAnonymously(): Promise<LoginState>

示例代码#

const app = cloudbase.init({  env: "xxxx-yyy"})
const auth = app.auth()await auth.signInAnonymously()

匿名登录转正示例

const app = cloudbase.init({  env: "xxxx-yyy"})
const auth = app.auth()// 1. 匿名登录await auth.signInAnonymously()
// 2. 获取accesstokenconst access_token = await auth.getAccessToken()
// 3. 转正注册await auth.signUp({  ...// 传参参考 Auth.signUp接口  anonymous_token: access_token})

Auth.setCustomSignFunc()#

接口描述#

设置获取自定义登录 ticket 函数

接口声明 setCustomSignFunc(getTickFn: GetCustomSignTicketFn): void

GetCustomSignTicketFn#

GetCustomSignTicketFn = () => Promise<string>

示例代码#

const app = cloudbase.init({  env: "xxxx-yyy"})const getTickFn = new Promise((resolve, reject))const auth = app.auth()await auth.setCustomSignFunc(getTickFn)

Auth.signInWithCustomTicket()#

接口描述#

自定义登录 接口声明 signInWithCustomTicket(): Promise<ILoginState>

示例代码#

const app = cloudbase.init({  env: "xxxx-yyy"})
const auth = app.auth()await auth.signInWithCustomTicket()

第三方平台登录相关#

Auth.genProviderRedirectUri()#

接口描述#

生成第三方平台授权 Uri (如微信二维码扫码授权网页)

接口声明 genProviderRedirectUri(params: GenProviderRedirectUriRequest): Promise<GenProviderRedirectUriResponse>

GenProviderRedirectUriRequest#

字段类型必填说明
provider_idstring第三方平台 ID,参考系统内置三方平台列表
provider_redirect_uristring第三方平台重定向 Uri,授权完成后,重定向时会在 url 中携带 code 参数
statestring用户自定义状态标识字段,识别三方平台回调来源
other_params{sign_out_uri?:string}其他参数

GenProviderRedirectUriResponse#

字段类型必填说明
uristring客户端请求
signout_uristring登出 Uri

示例代码#

const app = cloudbase.init({  env: "xxxx-yyy"})
const auth = app.auth()const providerId = "test_provider_id"const providerUri = "test_provider_redirect_uri"const state = "wx_open"const otherParams = { sign_out_uri: "test_sign_out_uri" }
// 三方平台授权登录示例
// 1. 获取第三方平台授权页地址(如微信授权)const { uri } = await auth.genProviderRedirectUri({  provider_id: providerId,  provider_redirect_uri: providerUri,  state: state,  other_params: otherParams})
// 2. 访问uri (如 location.href = uri)
// 3. 授权 (如微信扫码授权)
// 4. 回调至 provider_redirect_uri 地址(url query中携带 授权code,state等参数),此时检查 state 是否符合预期(如 自己设置的 wx_open)const provider_code = "your provider code"
// 5. state符合预期(微信开放平台授权 wx_open),则获取该三方平台tokenconst { provider_token } = await auth.grantProviderToken({  provider_id: "wx_open",  provider_redirect_uri: "cur page", // 指定三方平台跳回的 url 地址  provider_code: provider_code // 第三方平台跳转回页面时,url param 中携带的 code 参数})
// 6. 通过 provider_token 登录await auth.signInWithProvider({  provider_token: providerToken})

Auth.grantProviderToken()#

接口描述#

提供第三方平台登录 token

接口声明 grantProviderToken(params: GrantProviderTokenRequest): Promise<GrantProviderTokenResponse>

GrantProviderTokenRequest#

字段类型必填说明
provider_idstring第三方平台 ID,参考系统内置三方列表
provider_redirect_uristring第三方平台重定向 uri
provider_codestring第三方平台授权 code(重定向 uri 中携带)
provider_access_tokenstring第三方平台访问 token(重定向 uri 中携带)
provider_id_tokenstring第三方平台 ID token(重定向 uri 中携带)

GrantProviderTokenResponse#

字段类型必填说明
provider_tokenstring第三方平台 token
expires_innumber有效期

示例代码#

const app = cloudbase.init({  env: "xxxx-yyy"})
const auth = app.auth()const providerId = "wx_open" // 微信开放平台auth.grantProviderToken({  provider_id: providerId,  provider_redirect_uri: "cur page", // 指定三方平台跳回的 url 地址  provider_code: "provider code" // 第三方平台跳转回页面时,url param 中携带的 code 参数})

Auth.signInWithProvider()#

接口描述#

第三方平台登录

接口声明 signInWithProvider(params: SignInWithProviderRequest): Promise<LoginState>

SignInWithProviderRequest#
字段类型必填说明
provider_tokenstring第三方平台 token,参考 Auth.grantProviderToken

示例代码#

const app = cloudbase.init({  env: "xxxx-yyy"})
const auth = app.auth()const providerToken = "test_provider_token"auth.signInWithProvider({  provider_token: providerToken})

Auth.unbindProvider()#

接口描述#

解除第三方绑定

接口声明:unbindProvider(params: UnbindProviderRequest): Promise<void>

UnbindProviderRequest#
字段类型必填说明
provider_idstring第三方平台 ID,参考第三方绑定时回包的

示例代码#

const app = cloudbase.init({  env: "xxxx-yyy"})
const auth = app.auth()
// 完成登录后
// 获取绑定第三方平台IDconst { id } = await auth.getProviders()
await auth.unbindProvider({  provider_id: id})

Auth.getProviders()#

接口描述#

获取第三方绑定列表

接口声明:getProviders(): Promise<UserProfileProvider>

UserProfileProvider#
字段类型必填说明
idstring第三方平台 ID
provider_user_idstring第三方平台用户 ID
namestring第三方平台昵称

示例代码#

const app = cloudbase.init({  env: "xxxx-yyy"})
const auth = app.auth()
// 完成登录后
await auth.getProviders()

Auth.bindWithProvider()#

接口描述#

绑定第三方登录

接口声明 bindWithProvider(params: BindWithProviderRequest): Promise<void>

BindWithProviderRequest#
字段类型必填说明
provider_tokenstring第三方平台授权 token

示例代码#

const app = cloudbase.init({  env: "xxxx-yyy"})const provider_token = "test_provider_token" // 参考Auth.grantProviderToken 获取
const auth = app.auth()await auth.bindWithProvider({  provider_token})

验证/授权相关#

Auth.verify()#

接口描述#

验证码验证

接口声明 verify(params: VerifyRequest): Promise<VerifyResponse>

VerifyRequest#

字段类型必填说明
verification_codestring验证码
verification_idstring验证码 ID

VerifyResponse#

字段类型必填说明
verification_tokenstring验证码 token

示例代码#

const app = cloudbase.init({  env: "xxxx-yyy"})
const auth = app.auth()
// 例:手机号验证码/ 邮箱验证码注册
// 1. 发送手机验证码const phoneNumber = "+86 13800000000"const verification = await auth.getVerification({  phone_number: phoneNumber})
/*// 若使用邮箱验证,第一步代码改为const email = "test@example.com"const verification = await auth.getVerification({  email: email});*/const verificationCode = "000000"
await auth.verify({  verification_code: verificationCode,  verification_id: verification.verification_id})

Auth.getVerification()#

接口描述#

获取验证码

接口声明 getVerification(params: GetVerificationRequest): Promise<GetVerificationResponse>

GetVerificationRequest#

字段类型必填说明
phone_numberstring手机号
emailstring邮箱
targetstring|'ANY'target
usagestringusage

GetVerificationResponse#

字段类型必填说明
verification_idstring验证码 id
is_userstring用户

示例代码#

const app = cloudbase.init({  env: "xxxx-yyy"})
const auth = app.auth()
const verificationCode = "000000"const email = "test@example.com"const phoneNumber = "+86 13800000000"const usage = "test_usage"
await auth.getVerification({  phone_number: phoneNumber  // email: email,})

Auth.sudo()#

接口描述#

通过 sudo 接口获取高级操作权限,如修改用户密码,修改手机号,邮箱等操作

接口声明 ### Auth.sudo(params: SudoRequest): Promise<void>

SudoRequest#

字段类型必填说明
passwordstring旧密码
verification_tokenstringtoken 令牌,通过手机号或邮箱验证获取

示例代码#

const app = cloudbase.init({  env: "xxxx-yyy"})const oldPassWord = "test_old_password"
const auth = app.auth()const sudoRes = await auth.sudo({  password: oldPassWord})
console.log(sudoRes.sudo_token)

Auth.getAccessToken()#

接口描述#

获取访问凭证 accessToken

接口声明 ### Auth.getAccessToken(): Promise<{accessToken: string;env:string}>

示例代码#

const app = cloudbase.init({  env: "xxxx-yyy"})
const auth = app.auth()
// 某种方式登录后...
// 获取access_tokenconst { accessToken } = await auth.getAccessToken()
console.log(accessToken)

用户信息相关#

Auth.getCurrentUser()#

接口描述#

Auth.currentUser的异步操作,返回表示当前用户的 User 实例

签名:getCurrentUser(): Promise<User | null>

示例代码#

const app = cloudbase.init({  env: "xxxx-yyy",  clientId: "xxxx"})
// 执行某种登录之后...app  .auth()  .getCurrenUser()  .then((user) => {    // ...  })

Auth.bindPhoneNumber()#

接口描述#

绑定手机号

接口声明:bindPhone(params: BindPhoneRequest): Promise<void>

BindPhoneRequest#
字段类型必填说明
phone_numberstring注册所用手机号
sudo_tokenstringtoken 令牌
verification_tokenstring验证码 token

示例代码#

const app = cloudbase.init({  env: "xxxx-yyy"})
const auth = app.auth()
const phoneNumber = "+86 13800000000"// 获取验证码const verification = await auth.getVerification({  phone_number: phoneNumber})const verificationCode = "000000"
// 验证验证码的正确性const verificationTokenRes = await auth.verify({  verification_id: verification.verification_id,  verification_code: verificationCode})
// 获取 sudo_tokenconst sudo_token = await auth.sudo({  verification_token: verificationTokenRes.verification_token})
await auth.bindPhoneNumber({  phone_number: phoneNumber,  sudo_token,  verification_token: verificationToken.verification_token})

Auth.bindEmail()#

接口描述#

更新邮箱地址

接口声明:bindEmail(params: BindEmailRequest): Promise<void>

BindEmailRequest#
字段类型必填说明
emailstring邮箱地址
sudo_tokenstringtoken 令牌
verification_tokenstring验证码 token

示例代码#

const app = cloudbase.init({  env: "xxxx-yyy",});
const auth = app.auth();const email = "test@example.com";
// 获取邮箱验证码const verification = await auth.getVerification({  email: email});
const verificationCode = "000000";// 验证验证码的正确性const verificationTokenRes = await auth.verify({  verification_id: verification.verification_id,  verification_code: verificationCode,});
// 获取 sudo_tokenconst sudo_token = await auth.sudo({  verification_token: verificationTokenRes.verification_token})
await auth.bindEmail({  email: email,  sudo_token:sudoToken  verification_token:verificationTokenRes.verification_token});

Auth.setPassword()#

接口描述#

设置密码(已登录状态下,更新用户密码)

接口声明 setPassword(params: SetPasswordRequest): Promise<void>

SetPasswordRequest#

字段类型必填说明
new_passwordstring新密码
sudo_tokenstringtoken 令牌 (如果用户只开启三方登录, 没有设置密码的情况下,sudo token 为 "" 空字符串)

示例代码#

const app = cloudbase.init({  env: "xxxx-yyy"})const newPassWord = "test_new_password"const sudoToken = "test_sudo_token" // 参考 Auth.sudo 接口获取
const auth = app.auth()await auth.setPassword({  new_password: newPassWord,  sudo_token: sudoToken})

Auth.getUserInfo()#

接口描述#

获取用户信息失败 接口声明 getUserInfo(): Promise<UserInfo>

UserInfo#
字段类型说明
User.namestring用户昵称(区分与 登录用户名 User.username)
User.picturestring用户上传头像
User.phone_numberstring用户绑定手机号
User.email_verifiedboolean用户是否经过邮箱验证
User.birthdatestring用户生日
User.localestring用户设置语言
User.zoneinfostring时区
User.UserProfileProviderUserProfileProvider第三方平台配置
UserProfileProvider#
字段类型必填说明
idstring默认内置的三方 providerid,wx_open, wx_mp
provider_user_idstring第三方 provider 用户 id (如 wxopenid)
namestring名称
系统内置三方列表#
provider_id含义
wx_open微信开放平台
wx_mp微信公众号

示例代码#

const app = cloudbase.init({  env: "xxxx-yyy"})const newPassWord = "test_new_password"const sudoToken = "test_sudo_token"
const auth = app.auth()const userInfo = await auth.getUserInfo()

Auth.queryUser()#

warning

自定义登录场景和匿名登录场景,不支持使用该接口查询用户信息(自定义登录场景请在业务服务中自行查询用户信息,匿名登录场景不支持)

接口描述#

查询用户

接口声明 queryUser(queryObj: QueryUserProfileRequest): Promise<QueryUserProfileResponse>;

QueryUserProfileRequest#
字段类型必填说明
idArray<string>用户 uid 数组,最多支持查询 50 个 id 对应的用户
usernamestring用户名称
emailstring邮箱
phone_numberstring手机号
QueryUserProfileResponse#
字段类型必填说明
totalstring数量
dataSimpleUserProfile[]用户列表

SimpleUserProfile#

字段类型必填说明
substring下标
namestring名称
picturestring图片
genderstring性别
localestring地点
emailstring邮箱
phone_numberstring手机号

示例代码#

const app = cloudbase.init({  env: "xxxx-yyy"})
const auth = app.auth()const email = "test@example.com"const phoneNumber = "+86 13800000000"const username = "test_username"
const userInfo = await auth.queryUser({  username: username})

Auth.resetPassword()#

接口描述#

重置密码(用户忘记密码无法登录时,可使用该接口强制设置密码) 接口声明 resetPassword(params: ResetPasswordRequest): Promise<void>

ResetPasswordRequest#

字段类型必填说明
emailstring邮箱
phone_numberstring手机号
new_passwordstring新密码
verification_tokenstring验证 token

示例代码#

const app = cloudbase.init({  env: "xxxx-yyy"})
const auth = app.auth()const email = "testexample.com"const newPassword = "test_new_password"const phoneNumber = "+86 13800000000"const verification = await auth.getVerification({  phone_number: phoneNumber})const verificationCode = "000000"// 验证验证码的正确性const verificationToken = await auth.verify({  verification_id: verification.verification_id,  verification_code: verificationCode})
await auth.resetPassword({  // email: email,  phone_number: phoneNumber,  new_password: newPassword,  verification_token: verificationToken.verificationToken})

Auth.isUsernameRegistered()#

接口描述#

检查用户名是否被绑定过。

签名:isUsernameRegistered(username: string): Promise<boolean>

示例代码#

const app = cloudbase.init({  env: "xxxx-yyy"})
const auth = app.auth()
const username = "your_awesome_username"auth.isUsernameRegistered(username).then((registered) => {  //})

Auth.deleteMe()#

接口描述#

删除用户。

签名:deleteMe(params: WithSudoRequest): Promise<UserProfile>

示例代码#

const app = cloudbase.init({  env: "xxxx-yyy"})
const auth = app.auth()
// 1. 通过 sudo 操作获取 sudo_token,参考 Auth.sudo 方法
// 2. deleteMe
const user = await auth.deleteMe({  sudo_token: "your sudo_token"})

Auth.loginScope()#

接口描述#

查询用户是否为匿名登录状态

签名:loginScope(): Promise<string>

示例代码#

const app = cloudbase.init({  env: "xxxx-yyy"})
const auth = app.auth()
const username = "your_awesome_username"
// 经过某种方式登录后...
const loginScope = await auth.loginScope()if (loginScope === "anonymous") {  console.log("当前为匿名登录方式")}

LoginState#

LoginState 对象是对用户当前的登录态的抽象

Auth.hasLoginState()#

接口描述#

返回当前登录状态 LoginState,如果未登录,则返回 null

签名:hasLoginState(): LoginState | null

示例代码#

const app = cloudbase.init({  env: "xxxx-yyy",  clientId: "xxxx"})
const loginState = app.auth().hasLoginState()
if (loginState) {  // 登录态有效} else {  // 没有登录态,或者登录态已经失效}

Auth.getLoginState()#

接口描述#

Auth.hasLoginState()的异步操作,返回当前登录状态 LoginState,如果未登录,则返回 null

签名:getLoginState(): Promise<LoginState | null>

提示

此 API 是 hasLoginState 的异步模式,适用于本地存储为异步的平台,比如 React Native

示例代码#

const app = cloudbase.init({  env: "xxxx-yyy",  clientId: "xxxx"})
const loginState = app  .auth()  .getLoginState()  .then((loginState) => {    if (loginState) {      // 登录态有效    } else {      // 没有登录态,或者登录态已经失效    }  })

LoginState.user#

类型:User | null

表示当前用户,具体请参考 User

如果没有登录,则为 null

User#

User.update()#

接口描述#

更新用户信息

签名:update(userInfo): Promise<void>

示例代码#

const user = auth.currentUser
user  .update({    gender: "MALE" // 性别,取值仅限于 MALE、FEMALE、UNKNOWN  })  .then(() => {    // 更新用户信息成功  })

User.refresh()#

接口描述#

刷新本地用户信息。当用户在其他客户端更新用户信息之后,可以调用此接口同步更新之后的信息。

签名:refresh(): Promise<UserInfo>

示例代码#

const user = auth.currentUser
user.refresh().then(() => {  // 刷新用户信息成功})

错误码#

登录错误#

错误码说明
not_found用户不存在
password_not_set当前用户未设置密码,请使用验证码登录或第三方登录方式
invalid_password密码不正确
user_pending该用户未激活
user_blocked该用户被停用
invalid_status您已经超过了密码最大重试次数, 请稍后重试
invalid_two_factor二次验证码不匹配或已过时

注册错误#

错误码说明
failed_precondition你输入的手机号或邮箱已被注册,请使用其他号码

验证码相关错误#

错误码说明
failed_precondition从第三方获取用户信息失败
resource_exhausted你尝试过于频繁,请稍后重试
invalid_argument您输入的验证码不正确或已过期
aborted你尝试的次数过多,请返回首页,稍后重试
permission_denied您当前的会话已过期,请返回重试
captcha_required需要输入验证码, 需根据反机器人服务接入
captcha_invalid验证码不正确, 需根据反机器人服务接入

其他错误#

错误码说明
unreachable网络错误,请检查您的网络连接,稍后重试

验证码相关处理#

error==captcha_required 或 error==captcha_invalid 表示请求触发了验证码相关逻辑。需要进行机器验证。

验证码流程完成后,若业务接口返回 error 等于 captcha_required,表示请求需要 captcha_token 参数,尽可能使用本地的未过期的验证码。当 error 等于 captcha_invalid 时,表示验证码无效,需要需要重新获取验证码。在同一个验证流程内,captcha_invalid 最多尝试一次即可。

初始化验证码#

curl -X POST "https://${env}.ap-shanghai.tcb-api.tencentcloudapi.com/auth/v1/captcha/init" \   -H "Content-Type:application/json" \   -u ${clientID}:${clientSecrect}   -d \'{  "redirect_uri": "https://example.com/callback",  "state": "your_state string"}'
请求参数#

redirect_uri: (必传) 验证码验证完成后的地址。 state: (必传) 系统状态字符串,该字符串在验证码验证完成后后将 state 携带到。

响应 1:状态码 200 且返回 url 字段非空,需要展示验证码并完成验证#

如果用户请求比较频繁或存在其他风险,验证码服务会返回下面的形式。

{  "url": "https://exmaple.com/captcha.html",  "expires_in": 600}

此时表示,用户行为需要经过验证码验证才可以通过,请求成功后,客户端通过浏览器或 webview/iframe 等 打开 url 地址,比如上面的https://exmaple.com/captcha.html 用户在 web 中处理完成后,会自动重定向到下面的地址:(其中 captcha_token 为验证码 token,expires_in 为过期时间,单位为秒), https://example.com/callback?state=xxxxx&captcha_token=hbGciOiJeyJhbGciOiJSUAeyJhbGciOiJ&expires_in=600

业务方需要监听 redirect_uri 的地址变化,当地址为 appanme://com.package.name/callback 时,比对 state 是否和传入的相同,并获取到 captcha_token 和 expires_in。

若验证过程发生错误,验证页面会展示错误信息,用户点击返回后,验证页面会将错误信息 error 和 error_description 拼接到 redirect_uri 后重定向,例如:

https://example.com/callback?state=xxxxx&error=xxx&error_description=xxx

此时业务方可以根据需要恢复初始页或做其它处理。

响应 2:状态码非 200,需要进行错误处理#

如果用户请求比较频繁或存在其他风险,验证码服务会返回下面的形式。

{  "error": "resource_exhausted",  "error_description": "Your operation is too frequent, please try again later"}

此时客户端需要展示 error_descriprion, 可以结合 i18n 展示进行多语言展示。

拿到 captcha_token 再次请求#

拿到 captcha_token 后,将 captcha_token 放到 url 参数中进行请求;

比如,请求 /v1/example 返回 captcha_invalid 错误,此时,则需要再次请求 /v1/example?captcha_token=hbGciOiJeyJhbGciOiJSUAeyJhbGciOiJ 即可完成操作。