阿里云手机号登录(适合中国大陆业务)
配置阿里云 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 控制台
- 进入 身份管理 → 用户
- 点击 创建用户
- 填写必要的信息
- 在访问配置中选择 使用永久 AccessKey 访问
- 创建完成后,页面会自动回到用户列表页面
获取 AccessKey ID 和 AccessKey Secret
- 在用户列表找到刚创建的 RAM 用户,AccessKey 这一列会显示AccessKey ID、AccessKey Secret,点击复制
AccessKey ID、AccessKey Secret 只会在创建时显示一次,后续无法再次查看。如果丢失,只能禁用旧密钥并重新创建新的 AccessKey。
为 RAM 用户授权调用 Dypnsapi 的权限
- 在用户列表找到刚创建的 RAM 用户,点击
登录名称 / 显示名称进入用户详情页 - 点击 权限管理 → 新增授权
- 在 权限策略 步骤,搜索框中搜索
dypns,找到 AliyunDypnsReadOnlyAccess、 AliyunDypnsFullAccess 权限,点击选择
你也可以选择 PowerUserAccess 权限,这种权限 提供对阿里云服务和资源的完全访问权限,包含了短信、OSS等等服务的全部权限。为了最小权限原则,建议只授权 AliyunDypnsReadOnlyAccess、 AliyunDypnsFullAccess,它包含了号码认证服务的全部权限,但不涉及其它服务。
- 确认授权
填入本地与生产环境变量
本地开发写入 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。