合伙人端登录验证调整还有日志落地
This commit is contained in:
+10
-1
@@ -193,7 +193,16 @@ async function main() {
|
||||
body: JSON.stringify({}),
|
||||
});
|
||||
|
||||
console.log('11. Partner bill');
|
||||
console.log('11. Partner phone gate');
|
||||
const unknownPartner = await expectFail('PARTNER_H5', '/partner/auth/phone/check', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ phone: '13899999999' }),
|
||||
});
|
||||
if (!unknownPartner.includes('未找到合伙人账号')) {
|
||||
throw new Error(`Expected partner phone gate, got: ${unknownPartner}`);
|
||||
}
|
||||
|
||||
console.log('12. Partner bill');
|
||||
const partners = await req('HQ_WEB', '/admin/partners', { token: admin.accessToken });
|
||||
const partnerId = partners.items?.[0]?.id;
|
||||
if (partnerId) {
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
import { execSync } from 'node:child_process';
|
||||
|
||||
const API = process.env.SMOKE_API ?? 'http://localhost:3000/api/v1';
|
||||
const DEFAULT_MOCK_CODE = process.env.MOCK_SMS_CODE ?? '123456';
|
||||
const REDIS_CONTAINER = process.env.REDIS_CONTAINER ?? 'dukang-redis';
|
||||
|
||||
function sleep(ms) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
async function fetchJson(path, options = {}) {
|
||||
const res = await fetch(`${API}${path}`, options);
|
||||
return res.json();
|
||||
}
|
||||
|
||||
function readSmsCodeFromRedis(phone, scene) {
|
||||
const key = `dukang:sms:${scene}:${phone}`;
|
||||
try {
|
||||
const code = execSync(`docker exec ${REDIS_CONTAINER} redis-cli GET "${key}"`, {
|
||||
encoding: 'utf8',
|
||||
}).trim();
|
||||
if (code && code !== '(nil)') return code;
|
||||
} catch {
|
||||
/* docker/redis unavailable */
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export async function loadClientConfig() {
|
||||
const json = await fetchJson('/common/client-config');
|
||||
if (json.code !== 0) throw new Error(`client-config: ${json.message}`);
|
||||
return json.data;
|
||||
}
|
||||
|
||||
export async function resolveSmsCode(phone, scene) {
|
||||
const cfg = await loadClientConfig();
|
||||
if (cfg.mockSms) return DEFAULT_MOCK_CODE;
|
||||
|
||||
const fromRedis = readSmsCodeFromRedis(phone, scene);
|
||||
if (fromRedis) return fromRedis;
|
||||
|
||||
throw new Error(
|
||||
`SMS code not found for ${phone} (${scene}); enable MOCK_SMS or ensure Redis is reachable`,
|
||||
);
|
||||
}
|
||||
|
||||
export async function sendSmsOnce(clientApp, sendPath, phone, scene) {
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Client-App': clientApp,
|
||||
};
|
||||
const res = await fetch(`${API}${sendPath}`, {
|
||||
method: 'POST',
|
||||
headers,
|
||||
body: JSON.stringify({ phone, scene }),
|
||||
});
|
||||
return res.json();
|
||||
}
|
||||
|
||||
export async function sendSmsWithCooldown(clientApp, sendPath, phone, scene) {
|
||||
let json = await sendSmsOnce(clientApp, sendPath, phone, scene);
|
||||
if (json.code !== 0 && String(json.message).includes('过于频繁')) {
|
||||
await sleep(65_000);
|
||||
json = await sendSmsOnce(clientApp, sendPath, phone, scene);
|
||||
}
|
||||
if (json.code !== 0) {
|
||||
const existing = readSmsCodeFromRedis(phone, scene);
|
||||
if (existing) return { reusedCode: true };
|
||||
throw new Error(`${sendPath}: ${json.message}`);
|
||||
}
|
||||
return json.data;
|
||||
}
|
||||
|
||||
export async function loginWithSms(clientApp, phone, scene, loginPath, sendPath) {
|
||||
await sendSmsWithCooldown(clientApp, sendPath, phone, scene);
|
||||
const code = await resolveSmsCode(phone, scene);
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Client-App': clientApp,
|
||||
};
|
||||
const res = await fetch(`${API}${loginPath}`, {
|
||||
method: 'POST',
|
||||
headers,
|
||||
body: JSON.stringify({ phone, code }),
|
||||
});
|
||||
const json = await res.json();
|
||||
if (json.code !== 0) throw new Error(`${loginPath}: ${json.message}`);
|
||||
return json.data;
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* 合伙人登录 / 手机号校验专项冒烟(需 API 已启动)
|
||||
* 用法: node scripts/test-partner-auth.mjs
|
||||
*/
|
||||
import { loginWithSms } from './sms-test-helper.mjs';
|
||||
|
||||
const API = process.env.SMOKE_API ?? 'http://localhost:3000/api/v1';
|
||||
|
||||
async function req(clientApp, path, options = {}) {
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Client-App': clientApp,
|
||||
...(options.token ? { Authorization: `Bearer ${options.token}` } : {}),
|
||||
};
|
||||
const res = await fetch(`${API}${path}`, { ...options, headers, body: options.body });
|
||||
const json = await res.json();
|
||||
if (json.code !== 0) throw new Error(`${path}: ${json.message}`);
|
||||
return json.data;
|
||||
}
|
||||
|
||||
async function expectFail(clientApp, path, options = {}) {
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Client-App': clientApp,
|
||||
...(options.token ? { Authorization: `Bearer ${options.token}` } : {}),
|
||||
};
|
||||
const res = await fetch(`${API}${path}`, { ...options, headers, body: options.body });
|
||||
const json = await res.json();
|
||||
if (json.code === 0) throw new Error(`${path}: expected failure`);
|
||||
return json.message;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log('1. PARTNER phone/check unknown');
|
||||
const unknownCheck = await expectFail('PARTNER_H5', '/partner/auth/phone/check', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ phone: '13899999999' }),
|
||||
});
|
||||
if (!unknownCheck.includes('未找到合伙人账号')) throw new Error(`unexpected: ${unknownCheck}`);
|
||||
|
||||
console.log('2. PARTNER sms/send unknown');
|
||||
const unknownSms = await expectFail('PARTNER_H5', '/partner/auth/sms/send', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ phone: '13899999999', scene: 'PARTNER_LOGIN' }),
|
||||
});
|
||||
if (!unknownSms.includes('未找到合伙人账号')) throw new Error(`unexpected: ${unknownSms}`);
|
||||
|
||||
console.log('3. PARTNER phone/check + login bound phone');
|
||||
const check = await req('PARTNER_H5', '/partner/auth/phone/check', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ phone: '13700000001' }),
|
||||
});
|
||||
if (!check.ok || !check.maskedPhone) throw new Error('phone check failed');
|
||||
|
||||
const login = await loginWithSms(
|
||||
'PARTNER_H5',
|
||||
'13700000001',
|
||||
'PARTNER_LOGIN',
|
||||
'/partner/auth/login/sms',
|
||||
'/partner/auth/sms/send',
|
||||
);
|
||||
if (!login.accessToken) throw new Error('login missing token');
|
||||
|
||||
console.log('4. Admin partner logs list');
|
||||
const admin = await req('HQ_WEB', '/admin/auth/login/password', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
loginName: process.env.SUPER_ADMIN_LOGIN ?? 'admin',
|
||||
password: process.env.SUPER_ADMIN_PASSWORD ?? 'dukang@123!',
|
||||
}),
|
||||
});
|
||||
const logs = await req('HQ_WEB', '/admin/logs/partners?page=1&pageSize=10&category=login', {
|
||||
token: admin.accessToken,
|
||||
});
|
||||
if (!Array.isArray(logs.items)) throw new Error('partner logs missing items');
|
||||
const hasLogin = logs.items.some((r) => r.eventName === 'partner_sms_login' || r.eventName === 'partner_login_success');
|
||||
if (!hasLogin) throw new Error('partner login log not found');
|
||||
|
||||
console.log('\n✅ partner-auth tests passed');
|
||||
}
|
||||
|
||||
main().catch((e) => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user