feat(api/web): 实现API请求签名验证功能并优化测试环境配置
refactor(db): 重构查询条件类到query目录下 test: 添加登录流程测试脚本和测试数据 chore: 添加crypto-js依赖用于签名验证 ci: 配置测试环境数据库和端口设置
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
import CryptoJS from 'crypto-js'
|
||||
|
||||
const SIGNATURE_SECRET = 'NovalonManageSystemSecretKey2026'
|
||||
|
||||
export interface SignatureHeaders {
|
||||
'X-Signature': string
|
||||
'X-Timestamp': string
|
||||
'X-Nonce': string
|
||||
}
|
||||
|
||||
export function generateSignature(
|
||||
method: string,
|
||||
path: string,
|
||||
query: string = '',
|
||||
body: string = '',
|
||||
timestamp: number,
|
||||
nonce: string
|
||||
): string {
|
||||
const stringToSign = buildStringToSign(method, path, query, body, timestamp, nonce)
|
||||
|
||||
const signature = CryptoJS.HmacSHA256(stringToSign, SIGNATURE_SECRET)
|
||||
const signatureBase64 = CryptoJS.enc.Base64.stringify(signature)
|
||||
|
||||
return signatureBase64
|
||||
}
|
||||
|
||||
export function generateSignatureHeaders(
|
||||
method: string,
|
||||
url: string,
|
||||
body?: any
|
||||
): SignatureHeaders {
|
||||
const timestamp = Date.now()
|
||||
const nonce = generateNonce()
|
||||
|
||||
const { path, query } = parseUrl(url)
|
||||
const bodyString = ''
|
||||
|
||||
const signature = generateSignature(
|
||||
method.toUpperCase(),
|
||||
path,
|
||||
query || '',
|
||||
bodyString,
|
||||
timestamp,
|
||||
nonce
|
||||
)
|
||||
|
||||
return {
|
||||
'X-Signature': signature,
|
||||
'X-Timestamp': timestamp.toString(),
|
||||
'X-Nonce': nonce
|
||||
}
|
||||
}
|
||||
|
||||
function buildStringToSign(
|
||||
method: string,
|
||||
path: string,
|
||||
query: string,
|
||||
body: string,
|
||||
timestamp: number,
|
||||
nonce: string
|
||||
): string {
|
||||
return [
|
||||
method,
|
||||
path,
|
||||
query || '',
|
||||
body || '',
|
||||
timestamp.toString(),
|
||||
nonce
|
||||
].join('\n')
|
||||
}
|
||||
|
||||
function generateNonce(): string {
|
||||
const timestamp = Date.now().toString(36)
|
||||
const randomPart = Math.random().toString(36).substring(2, 15)
|
||||
return `${timestamp}-${randomPart}`
|
||||
}
|
||||
|
||||
function parseUrl(url: string): { path: string; query: string } {
|
||||
if (url.startsWith('http://') || url.startsWith('https://')) {
|
||||
const urlObj = new URL(url)
|
||||
return {
|
||||
path: urlObj.pathname,
|
||||
query: urlObj.search.substring(1)
|
||||
}
|
||||
}
|
||||
|
||||
const queryIndex = url.indexOf('?')
|
||||
if (queryIndex === -1) {
|
||||
return { path: url, query: '' }
|
||||
}
|
||||
|
||||
return {
|
||||
path: url.substring(0, queryIndex),
|
||||
query: url.substring(queryIndex + 1)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user