c2820d6b07
根本原因: - RoleAuthManager直接向后端发送请求(http://localhost:8084) - 绕过了gateway的签名验证 - 导致认证失败 修复方案: - 修改API_BASE_URL指向gateway(http://localhost:8080) - 确保所有请求都通过gateway进行签名验证 影响范围: - Token注入登录测试 - 所有需要认证的测试
90 lines
2.5 KiB
TypeScript
90 lines
2.5 KiB
TypeScript
import { RoleFactory } from '../roles/role-factory';
|
|
import crypto from 'crypto';
|
|
|
|
interface TokenCache {
|
|
token: string;
|
|
expiresAt: number;
|
|
}
|
|
|
|
const SIGNATURE_SECRET = 'NovalonManageSystemSecretKey2026';
|
|
|
|
export class RoleAuthManager {
|
|
private static tokenCache: Map<string, TokenCache> = new Map();
|
|
private static readonly API_BASE_URL = process.env.VITE_API_BASE_URL || 'http://localhost:8080';
|
|
private static readonly TOKEN_EXPIRY_BUFFER = 60000;
|
|
|
|
static async getRoleToken(roleName: string): Promise<string> {
|
|
const cached = this.tokenCache.get(roleName);
|
|
|
|
if (cached && cached.expiresAt > Date.now() + this.TOKEN_EXPIRY_BUFFER) {
|
|
return cached.token;
|
|
}
|
|
|
|
const role = RoleFactory.getRole(roleName);
|
|
const token = await this.authenticateWithBackend(role.credentials);
|
|
|
|
this.tokenCache.set(roleName, {
|
|
token,
|
|
expiresAt: Date.now() + 3600000
|
|
});
|
|
|
|
return token;
|
|
}
|
|
|
|
private static generateSignatureHeaders(method: string, path: string, body: string): Record<string, string> {
|
|
const timestamp = Date.now();
|
|
const nonce = `${timestamp.toString(36)}-${Math.random().toString(36).substring(2, 15)}`;
|
|
|
|
const stringToSign = [
|
|
method.toUpperCase(),
|
|
path,
|
|
'',
|
|
'',
|
|
timestamp.toString(),
|
|
nonce
|
|
].join('\n');
|
|
|
|
const signature = crypto
|
|
.createHmac('sha256', SIGNATURE_SECRET)
|
|
.update(stringToSign)
|
|
.digest('base64');
|
|
|
|
return {
|
|
'X-Signature': signature,
|
|
'X-Timestamp': timestamp.toString(),
|
|
'X-Nonce': nonce
|
|
};
|
|
}
|
|
|
|
private static async authenticateWithBackend(credentials: { username: string; password: string }): Promise<string> {
|
|
const path = '/api/auth/login';
|
|
const body = JSON.stringify(credentials);
|
|
const signatureHeaders = this.generateSignatureHeaders('POST', path, body);
|
|
|
|
const response = await fetch(`${this.API_BASE_URL}${path}`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
...signatureHeaders
|
|
},
|
|
body,
|
|
});
|
|
|
|
if (!response.ok) {
|
|
const errorText = await response.text();
|
|
throw new Error(`Authentication failed for user ${credentials.username}: ${response.statusText} - ${errorText}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
return data.data?.token || data.token;
|
|
}
|
|
|
|
static clearCache(): void {
|
|
this.tokenCache.clear();
|
|
}
|
|
|
|
static clearRoleToken(roleName: string): void {
|
|
this.tokenCache.delete(roleName);
|
|
}
|
|
}
|