阿里云手机号登录(适合中国大陆业务)
配置阿里云 Dypnsapi 短信验证码登录
阿里云手机号登录
EasyStarter 已经内置基于 Better Auth phone-number plugin 的手机号登录。服务端通过阿里云号码认证服务 Dypnsapi 发送和校验短信验证码,客户端继续使用 Better Auth 的 phoneNumber.sendOtp 与 phoneNumber.verify,不需要额外新增自定义认证接口。
如果你的产品主要在国内部署,建议把手机号登录作为首选甚至唯一登录方式。国内用户对手机号验证码登录的接受度最高,GitHub / Google / Apple 这类 OAuth 登录在国内访问稳定性、账号覆盖率和合规配置上都更麻烦;邮箱密码登录也可以保留,但不是必须。也就是说,面向国内场景时,只配置阿里云手机号登录即可,其它登录方式都可以不启用、不申请、不写环境变量。
当前内置流程只支持中国大陆手机号:
| 项目 | 当前配置 |
|---|---|
| 手机号格式 | +86 E.164 格式,例如 +8613800138000 |
| 发送接口 | SendSmsVerifyCode |
| 校验接口 | CheckSmsVerifyCode |
| 服务端 Provider | apps/server/src/sms/providers/aliyun.ts |
| Better Auth 配置 | apps/server/src/lib/auth.ts |
所需环境变量
ALIBABA_CLOUD_ACCESS_KEY_ID=
ALIBABA_CLOUD_ACCESS_KEY_SECRET=这两个值是服务端调用阿里云 OpenAPI 的长期访问凭证。不要提交到 Git,也不要放到前端环境变量中。
如果你只保留手机号登录,GITHUB_CLIENT_ID、GITHUB_CLIENT_SECRET、GOOGLE_CLIENT_ID、GOOGLE_CLIENT_SECRET 等 OAuth 变量可以不配置。生产环境只需要保留 Better Auth 会话所需的基础变量和这里的阿里云 AccessKey。
开通号码认证服务
先确认阿里云账号已经开通号码认证服务,并且账号可调用 Dypnsapi 的短信认证接口。
官方接口文档:SendSmsVerifyCode
阿里云文档中说明,SendSmsVerifyCode 是号码认证服务的短信验证码发送接口。它使用 Dypnsapi 产品下的 2017-05-25 API 版本,并且授权 Action 为 dypns:SendSmsVerifyCode。
创建 RAM 用户并授权
推荐使用 RAM 用户的 AccessKey,不要直接使用阿里云主账号 AccessKey。
- 登录 阿里云 RAM 控制台
- 进入 身份管理 → 用户
- 点击 创建用户
- 填写登录名称与显示名称
- 在访问方式中选择 OpenAPI 调用访问
- 创建完成后,为该 RAM 用户授予号码认证服务所需权限
如果你希望权限更收敛,可以创建自定义策略,只允许调用短信验证码相关接口:
{
"Version": "1",
"Statement": [
{
"Effect": "Allow",
"Action": [
"dypns:SendSmsVerifyCode",
"dypns:CheckSmsVerifyCode"
],
"Resource": "*"
}
]
}如果你还在调试阶段,也可以先使用阿里云提供的号码认证服务相关系统策略,跑通后再收敛权限。
获取 AccessKey ID 和 AccessKey Secret
官方文档:创建 AccessKey
- 登录 阿里云 RAM 控制台
- 进入 身份管理 → 用户
- 点击上一步创建的 RAM 用户
- 打开 认证管理 或 AccessKey 标签
- 点击 创建 AccessKey
- 根据控制台提示完成安全校验
- 创建成功后,立即复制并保存:
AccessKey ID→ALIBABA_CLOUD_ACCESS_KEY_IDAccessKey Secret→ALIBABA_CLOUD_ACCESS_KEY_SECRET
AccessKey Secret 只会在创建时显示一次,后续无法再次查看。如果丢失,只能禁用旧密钥并重新创建新的 AccessKey。
填入本地与生产环境变量
本地开发写入 apps/server/.dev.vars:
ALIBABA_CLOUD_ACCESS_KEY_ID=your-access-key-id
ALIBABA_CLOUD_ACCESS_KEY_SECRET=your-access-key-secret生产部署写入 apps/server/.env.production:
ALIBABA_CLOUD_ACCESS_KEY_ID=your-access-key-id
ALIBABA_CLOUD_ACCESS_KEY_SECRET=your-access-key-secret.env.production 只用于通过 Wrangler 批量推送到 Cloudflare Workers Secrets,不参与前端构建,也不应该提交到仓库。
推送生产 Secrets
部署到 Cloudflare Workers 前,把生产密钥推送到 Workers Secrets:
pnpm -F server secrets:bulk:production推送成功后,Worker 运行时可以通过 env.ALIBABA_CLOUD_ACCESS_KEY_ID 和 env.ALIBABA_CLOUD_ACCESS_KEY_SECRET 读取密钥。更新密钥时重新执行这条命令即可,不需要因为 Secret 变化而重新部署代码。
保持阿里云验证码参数不变
EasyStarter 内置 Provider 已经按阿里云 SendSmsVerifyCode 文档锁定以下参数:
const ALIYUN_SMS_VERSION = "2017-05-25";
const ALIYUN_SMS_SIGN_NAME = "速通互联验证码";
const ALIYUN_SMS_TEMPLATE_CODE = "100001";这三个值不要修改:
| 常量 | 对应阿里云参数 | 为什么不能改 |
|---|---|---|
ALIYUN_SMS_VERSION | OpenAPI 版本 | Dypnsapi 的 SendSmsVerifyCode 接口版本就是 2017-05-25 |
ALIYUN_SMS_SIGN_NAME | SignName | 文档示例使用号码认证服务赠送签名 速通互联验证码,该接口暂不支持普通自定义签名 |
ALIYUN_SMS_TEMPLATE_CODE | TemplateCode | 赠送签名必须搭配赠送模板,当前模板 Code 为 100001 |
这里使用的是号码认证服务 Dypnsapi 的短信认证接口,不是普通短信服务 Dysmsapi 的 SendSms。不要把普通短信服务里申请的 SMS_... 模板码替换到这里。
本地验证手机号登录
启动服务端与客户端后,在登录页选择手机号登录:
pnpm dev:server
pnpm dev:web输入中国大陆手机号后,前端会调用:
POST /api/auth/phone-number/send-otp提交验证码时会调用:
POST /api/auth/phone-number/verify服务端会把 +86 号码拆成阿里云需要的 CountryCode=86 和本地手机号,然后由阿里云生成、发送并校验验证码。
常见问题
为什么不自己生成验证码?
当前实现使用 TemplateParam={"code":"##code##","min":"5"},让阿里云生成验证码。这样后续校验可以继续调用 CheckSmsVerifyCode,服务端不需要自己保存验证码。
为什么不能换成自己的短信签名?
SendSmsVerifyCode 属于号码认证服务。阿里云文档说明,赠送签名必须搭配赠送模板使用,并且暂不支持使用自定义签名。当前内置值与官方文档示例保持一致。
AccessKey 泄露怎么办?
立即在 RAM 控制台禁用或删除泄露的 AccessKey,重新创建新的 AccessKey,并重新推送 apps/server/.env.production 到 Workers Secrets。