forked from wangziqi/gongxue-base
fix: validate PNVS provider rows for alias env
This commit is contained in:
@@ -36,7 +36,7 @@
|
||||
|
||||
| 能力 | 状态 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| 短信验证码登录 | 可联调 | 已有验证码、冷却、登录事件;推荐生产使用阿里云 PNVS 短信认证 `aliyun-pnvs`,由阿里云生成和核验验证码,本地只保存发送流水/`outId`/审计;传统阿里云短信、腾讯云短信和开发 mock provider 保留兼容,生产仍需跑真实手机号远程 smoke |
|
||||
| 短信验证码登录 | 可联调 | 已有验证码、冷却、登录事件;生产统一使用阿里云 PNVS 短信认证 `aliyun-pnvs`,由阿里云生成和核验验证码,本地只保存发送流水/`outId`/审计;传统阿里云短信、腾讯云短信和开发 mock provider 保留兼容但不作为上线路径,生产仍需跑真实手机号远程 smoke |
|
||||
| 迁移期 session | 迁移期 | `tk_` token hash 存在 `app_private.auth_sessions`,用户态接口已优先解析 bearer session 并拒绝伪造 userId/tenantId |
|
||||
| Supabase Auth JWT | 可联调 | API 已用 Bearer JWT 验签并通过 `auth.users.id -> platform_users.auth_user_id -> tenant_memberships` 映射业务身份;支持 HS256 JWT secret 或 JWKS;测试覆盖学生、租户管理员、平台管理员、错租户、坏签名 |
|
||||
| 微信小程序登录 | 可联调 | `/api/auth/oauth/wechat-miniapp` 已接 `code2Session`、openid/unionid 身份、session 签发和登录审计 |
|
||||
|
||||
@@ -154,7 +154,7 @@ Taro H5 构建存在 webpack asset size warning,这是前端包体优化事项
|
||||
- 生产 API 已能启动,`https://api.tjszsb.com/api/tenant/resolve?host=app.tjszsb.com` 已返回 `master` 租户。
|
||||
- Supabase self-hosted 运行在 `/opt/tiku-saas/supabase-project`,Kong 通过 Nginx 暴露到 `https://supabase.tjszsb.com`。
|
||||
- 线上 H5 公开配置文件在 `/srv/tiku-saas/www/*/runtime-config.json`,密钥只允许放 `supabasePublishableKey` 这类公开 key。
|
||||
- 短信登录推荐生产使用 `AUTH_SMS_PROVIDER=aliyun-pnvs`。阿里云 AccessKey/Secret 只写入 `app_private.tenant_secrets(secret_scope='sms', secret_key='aliyun-pnvs')`,不要写进 `/etc/tiku-saas/api.env` 或 H5 `runtime-config.json`。
|
||||
- 短信验证码登录生产必须使用 `AUTH_SMS_PROVIDER=aliyun-pnvs`。阿里云 AccessKey/Secret 只写入 `app_private.tenant_secrets(secret_scope='sms', secret_key='aliyun-pnvs')`,不要写进 `/etc/tiku-saas/api.env` 或 H5 `runtime-config.json`。
|
||||
|
||||
配置 PNVS provider 推荐用仓库脚本写入数据库,避免手写 SQL 时把密钥打进命令历史。生产环境建议临时关闭 shell history,再用 `read -s` 输入 AccessKeySecret:
|
||||
|
||||
|
||||
@@ -219,10 +219,28 @@ WORKER_ASSET_SECURITY_SCANNER=metadata_rules,http
|
||||
WORKER_ASSET_SECURITY_SCAN_HTTP_ENDPOINT=https://scanner.gongxue100.com/api/scan
|
||||
WORKER_ASSET_SECURITY_SCAN_HTTP_TOKEN=s3cure-asset-scanner-token-2026-06-29-stuvwx
|
||||
WORKER_ASSET_SECURITY_SCAN_FAIL_OPEN=false
|
||||
`);
|
||||
`, {
|
||||
providerRows: [
|
||||
{
|
||||
source: 'auth',
|
||||
tenantId: 'tenant-pnvs',
|
||||
provider: 'aliyun-pnvs',
|
||||
configPublic: {
|
||||
signName: '短信签名',
|
||||
templateCode: 'SMS_123456789',
|
||||
endpoint: 'https://dypnsapi.aliyuncs.com',
|
||||
templateParam: { code: '##code##', min: '5' },
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
assert.equal(safeAliyunPnvsUnderscoreAlias.status, 0, `aliyun_pnvs readiness should pass without blockers: ${safeAliyunPnvsUnderscoreAlias.stdout} ${safeAliyunPnvsUnderscoreAlias.stderr}`);
|
||||
assert.equal(safeAliyunPnvsUnderscoreAlias.payload.summary?.blocker, 0, 'aliyun_pnvs readiness should have no blockers');
|
||||
assert.ok(
|
||||
safeAliyunPnvsUnderscoreAlias.payload.checks?.some(item => item.id === 'db.auth_sms_provider_configured' && item.status === 'pass'),
|
||||
'aliyun_pnvs readiness should still validate matching PNVS provider rows',
|
||||
);
|
||||
|
||||
const pnvsTemplateParamWarning = runReadiness(
|
||||
`
|
||||
|
||||
@@ -160,19 +160,23 @@ function normalizeProvider(value) {
|
||||
return String(value || '').trim().toLowerCase();
|
||||
}
|
||||
|
||||
function normalizeSmsProvider(value) {
|
||||
return normalizeProvider(value).replace(/[_\s]/g, '-');
|
||||
}
|
||||
|
||||
function providerIn(provider, aliases) {
|
||||
return aliases.has(normalizeProvider(provider));
|
||||
}
|
||||
|
||||
function currentSmsProviderAliases() {
|
||||
const provider = normalizeProvider(env('AUTH_SMS_PROVIDER', 'mock')).replace(/_/g, '-');
|
||||
const provider = normalizeSmsProvider(env('AUTH_SMS_PROVIDER', 'mock'));
|
||||
if (AUTH_PROVIDER_ALIASES.aliyunPnvs.has(provider)) return { provider: 'aliyun-pnvs', aliases: AUTH_PROVIDER_ALIASES.aliyunPnvs };
|
||||
return { provider, aliases: new Set([provider]) };
|
||||
}
|
||||
|
||||
function validateActiveSmsProviderRows(rows, sourceLabel = 'database') {
|
||||
const expected = currentSmsProviderAliases();
|
||||
if (!PRODUCTION_SMS_PROVIDERS.has(normalizeProvider(env('AUTH_SMS_PROVIDER', 'mock')))) return;
|
||||
if (!PRODUCTION_SMS_PROVIDERS.has(normalizeSmsProvider(env('AUTH_SMS_PROVIDER', 'mock')))) return;
|
||||
const activeRows = rows.filter(row => row.source === 'auth' && providerIn(row.provider, expected.aliases));
|
||||
if (activeRows.length === 0) {
|
||||
block('db.auth_sms_provider_configured', 'AUTH_SMS_PROVIDER must have a matching active/testing tenant_auth_providers row', {
|
||||
@@ -565,7 +569,7 @@ function validateEnv() {
|
||||
}
|
||||
}
|
||||
|
||||
const authSmsProvider = normalizeProvider(env('AUTH_SMS_PROVIDER', 'mock')).replace(/[_\s]/g, '-');
|
||||
const authSmsProvider = normalizeSmsProvider(env('AUTH_SMS_PROVIDER', 'mock'));
|
||||
if (!PRODUCTION_SMS_PROVIDERS.has(authSmsProvider)) {
|
||||
block('env.auth_sms_provider', 'AUTH_SMS_PROVIDER must be aliyun-pnvs in production', {
|
||||
provider: authSmsProvider || '(empty)',
|
||||
|
||||
Reference in New Issue
Block a user