forked from wangziqi/gongxue-base
docs: lock production SMS on PNVS
This commit is contained in:
@@ -46,13 +46,13 @@ Supabase Auth 可继续作为最终 JWT 用户体系目标;本地重构期先
|
||||
|
||||
## 短信 Provider
|
||||
|
||||
本地默认是 `AUTH_SMS_PROVIDER=mock`,仅开发环境返回 `debugCode`。生产环境只允许 `aliyun/aliyun-sms`、`aliyun-pnvs/aliyun-sms-auth` 或 `tencent/tencent-sms`;如果仍为 mock 或写成未知 provider,API 启动和 `readiness:production` 都会直接失败。
|
||||
本地默认是 `AUTH_SMS_PROVIDER=mock`,仅开发环境返回 `debugCode`。本项目生产短信验证码登录统一使用 `AUTH_SMS_PROVIDER=aliyun-pnvs`;传统阿里云短信和腾讯云短信 adapter 仅作为兼容/回滚代码路径,不作为当前生产上线方案。如果生产仍为 mock、未知 provider,或数据库未配置匹配的 PNVS provider,API 启动、`readiness:production:db` 和上线 gate 都会失败。
|
||||
|
||||
真实 provider:
|
||||
|
||||
- `aliyun` / `aliyun-sms`:阿里云短信 `SendSms`,需要 AccessKey、签名、模板 ID。
|
||||
- `aliyun-pnvs` / `aliyun-sms-auth`:阿里云 PNVS 短信认证服务,调用 `SendSmsVerifyCode` 发送,调用 `CheckSmsVerifyCode` 核验;验证码由阿里云生成并校验,本地不保存明文验证码。
|
||||
- `tencent` / `tencent-sms`:腾讯云短信 `SendSms`,需要 SecretId、SecretKey、SdkAppId、签名、模板 ID。
|
||||
- `aliyun-pnvs` / `aliyun-sms-auth`:当前生产方案,调用 `SendSmsVerifyCode` 发送,调用 `CheckSmsVerifyCode` 核验;验证码由阿里云生成并校验,本地不保存明文验证码。
|
||||
- `aliyun` / `aliyun-sms`:阿里云短信 `SendSms` 兼容路径,需要 AccessKey、签名、模板 ID。
|
||||
- `tencent` / `tencent-sms`:腾讯云短信 `SendSms` 兼容路径,需要 SecretId、SecretKey、SdkAppId、签名、模板 ID。
|
||||
|
||||
PNVS 只用于手机号登录和 `bind_phone` 这类验证码认证场景,不用于营销短信、催缴短信或 CRM 触达。平台催缴里的 `channel='sms'` 是内部提醒渠道枚举;外部催缴通知当前通过 generic/钉钉/飞书/企微 webhook worker 发送,不能复用 PNVS 的验证码接口。
|
||||
|
||||
@@ -62,7 +62,8 @@ PNVS 只用于手机号登录和 `bind_phone` 这类验证码认证场景,不
|
||||
- 租户级密钥写 `app_private.tenant_secrets(secret_scope='sms')` 或生产 Vault。
|
||||
- 前端只能看到 provider 是否启用、签名展示名、隐私协议链接等非敏感配置。
|
||||
- provider endpoint 默认使用官方域名,生产环境只允许 HTTPS 官方域名;本地测试可使用 `localhost/127.0.0.1` fake server。
|
||||
- `readiness:production:db` 会检查 active/testing 短信 provider 的 `signName/templateCode` 或 `smsSdkAppId/signName/templateId`,并阻断公开配置里的 secret-like 字段。
|
||||
- `npm run diagnose:aliyun-pnvs` 会只读检查生产 env、PNVS `tenant_auth_providers` 和 `tenant_secrets` 是否对齐;输出只包含密钥长度和脱敏前后缀。
|
||||
- `readiness:production:db` 会检查 active/testing PNVS provider 的 `signName/templateCode`、secretRef 和私密 `tenant_secrets`,并阻断公开配置里的 secret-like 字段。
|
||||
|
||||
### 阿里云 PNVS 短信认证配置示例
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
- 已覆盖学生、租户管理员、平台管理员、错租户、坏签名、禁用 legacy header 的 API 集成测试。
|
||||
- 已补自定义角色模板、菜单/模块/字段级配置 API、班级/学生范围权限;已新增 `npm run test:rls` 本地动态 RLS 深测,覆盖主租户、合作商租户、无租户 claim、平台管理员旁路和跨租户写入拒绝;已新增 `npm run smoke:auth:remote` 用真实 Supabase access token 验收云端 Auth/JWKS 映射;继续在预生产/生产执行并留档。
|
||||
- 前端联调时禁止继续使用 `x-user-id`;`x-tenant-id` 只作为租户上下文,不能作为身份依据。
|
||||
- 生产 `.env` 必须通过 `readiness:production`:短信 provider 只允许阿里云/腾讯云,禁止 mock/未知值,禁止弱密钥、`CORS=*` 和 legacy 身份头。生产数据库还必须通过 `readiness:production:db`,校验租户短信/OAuth/支付 provider 的公开配置、HTTPS 回调、私密 `tenant_secrets` 和 RLS。
|
||||
- 生产 `.env` 必须通过 `readiness:production`:短信验证码 provider 使用 `AUTH_SMS_PROVIDER=aliyun-pnvs`,禁止 mock/未知值,禁止弱密钥、`CORS=*` 和 legacy 身份头。生产数据库还必须通过 `readiness:production:db` 和 `npm run diagnose:aliyun-pnvs`,校验租户 PNVS/OAuth/支付 provider 的公开配置、HTTPS 回调、私密 `tenant_secrets` 和 RLS。
|
||||
|
||||
2. 对象存储
|
||||
- 已接阿里云 OSS、腾讯云 COS、Supabase Storage 的上传/下载签名 provider。
|
||||
@@ -109,7 +109,7 @@
|
||||
- 租户自有商户收款和平台代收/服务商模式。
|
||||
|
||||
2. 国内登录和短信
|
||||
- 已完成阿里云 PNVS 短信认证后端接入、远程短信登录 smoke 脚本、传统阿里云短信/腾讯云短信兼容 adapter 和本地 fake endpoint 测试。
|
||||
- 已完成阿里云 PNVS 短信认证后端接入、只读配置诊断脚本、远程短信登录 smoke 脚本、传统阿里云短信/腾讯云短信兼容 adapter 和本地 fake endpoint 测试;生产验证码登录按 PNVS 验收,传统 provider 不作为当前上线方案。
|
||||
- 已完成微信小程序 `code2Session` 登录主链路。
|
||||
- 已完成手机号绑定/换绑、微信网页登录、QQ 登录基础 API;继续补真实生产账号、回调域名和开放平台联调。
|
||||
- 本地阶段不等待真实密钥,继续用 mock/fake provider 验证验证码、账号合并、登录审计、session 签发和错误处理;真实密钥、合法域名和开放平台错误码等上云后再联调。
|
||||
|
||||
@@ -130,7 +130,7 @@ PNVS 只验收手机号登录/换绑验证码链路。催缴、营销、CRM 等
|
||||
ALLOW_LEGACY_AUTH_HEADERS=false
|
||||
ALLOW_PLATFORM_ADMIN_KEY=false
|
||||
CORS_ORIGIN=https://student.example.com,https://tenant-admin.example.com,https://platform-admin.example.com
|
||||
AUTH_SMS_PROVIDER=aliyun-pnvs、aliyun 或 tencent
|
||||
AUTH_SMS_PROVIDER=aliyun-pnvs
|
||||
```
|
||||
|
||||
生产 worker 推荐:
|
||||
|
||||
@@ -9,6 +9,7 @@ const deployEnvExample = fs.readFileSync(path.join(process.cwd(), 'scripts/deplo
|
||||
const providerDoc = fs.readFileSync(path.join(process.cwd(), 'docs/refactor/auth-payment-provider-plan.md'), 'utf8');
|
||||
const launchChecklist = fs.readFileSync(path.join(process.cwd(), 'docs/refactor/web-launch-acceptance-checklist.md'), 'utf8');
|
||||
const readinessSource = fs.readFileSync(path.join(process.cwd(), 'scripts/production-readiness-check.js'), 'utf8');
|
||||
const packageJson = fs.readFileSync(path.join(process.cwd(), 'package.json'), 'utf8');
|
||||
const tenantProviderConfigSource = fs.readFileSync(path.join(process.cwd(), 'apps/api/src/core/tenant-provider-config.ts'), 'utf8');
|
||||
const platformDunningNotificationWorker = fs.readFileSync(path.join(process.cwd(), 'apps/worker/src/jobs/platform-dunning-notifications.ts'), 'utf8');
|
||||
|
||||
@@ -30,6 +31,8 @@ assert.match(providerDoc, /SendSmsVerifyCode/, 'provider doc should document PNV
|
||||
assert.match(providerDoc, /CheckSmsVerifyCode/, 'provider doc should document PNVS verify action');
|
||||
assert.match(providerDoc, /PNVS 只用于手机号登录和 `bind_phone`/, 'provider doc should constrain PNVS to verification-code auth flows');
|
||||
assert.doesNotMatch(platformDunningNotificationWorker, /aliyun-pnvs|SendSmsVerifyCode|CheckSmsVerifyCode/, 'platform dunning notifications must not use PNVS verification APIs');
|
||||
assert.match(launchChecklist, /AUTH_SMS_PROVIDER=aliyun-pnvs/, 'launch checklist should allow aliyun-pnvs');
|
||||
assert.match(packageJson, /diagnose:aliyun-pnvs/, 'package scripts should expose PNVS diagnostics');
|
||||
assert.match(launchChecklist, /AUTH_SMS_PROVIDER=aliyun-pnvs\s*```/, 'launch checklist should require aliyun-pnvs for production SMS verification');
|
||||
assert.match(launchChecklist, /diagnose:aliyun-pnvs/, 'launch checklist should run PNVS diagnostics before remote smoke');
|
||||
|
||||
console.log('[PASS] Aliyun PNVS provider contract');
|
||||
|
||||
2
scripts/deploy/env/api.env.example
vendored
2
scripts/deploy/env/api.env.example
vendored
@@ -18,7 +18,7 @@ AUTH_SESSION_SECRET=replace-with-strong-random-session-secret
|
||||
AUTH_CODE_PEPPER=replace-with-strong-random-code-pepper
|
||||
PLATFORM_ADMIN_API_KEY=replace-with-strong-random-platform-admin-key
|
||||
|
||||
# Supported production values: aliyun, aliyun-pnvs, tencent.
|
||||
# Production SMS verification uses aliyun-pnvs. Traditional aliyun/tencent adapters are compatibility paths only.
|
||||
# Tenant-level SMS AccessKey/SecretKey live in app_private.tenant_secrets, not in this env file.
|
||||
AUTH_SMS_PROVIDER=aliyun-pnvs
|
||||
|
||||
|
||||
Reference in New Issue
Block a user