Files
makemd/server/src/api/controllers/RiskControlController.ts

221 lines
5.8 KiB
TypeScript
Raw Normal View History

/**
* [BE-CTL-018] AI控制器
* AI介入RESTful API接口
* AI注意: 所有风控AI决策必须通过此控制器
*/
import { Request, Response } from 'express';
import { RiskRadarService } from '../../services/security/RiskRadarService';
import {
makeAIDecision,
DecisionType,
DecisionResult,
RiskLevel,
} from '../middleware/AIDecisionMiddleware';
import { logger } from '../../utils/logger';
export class RiskControlController {
/**
* POST /api/v1/risk/ai-decision
* AI决策
*/
static async makeDecision(req: Request, res: Response) {
try {
const { tenantId, operatorId, productId, riskType, transactionData } = req.body;
if (!tenantId || !operatorId) {
return res.status(400).json({
success: false,
error: 'MISSING_REQUIRED_FIELDS',
message: '缺少必要字段',
});
}
const aiDecision = makeAIDecision({
tenantId,
operatorId,
businessType: DecisionType.RISK_CONTROL,
operationType: riskType || 'TRANSACTION_RISK',
targetIds: productId ? [productId] : [],
customParams: {
riskType,
fraudScore: transactionData?.fraudScore || 0.3,
isHighRisk: (transactionData?.fraudScore || 0.3) > 0.7,
isObviousFraud: (transactionData?.fraudScore || 0.3) > 0.9,
amount: transactionData?.amount,
},
});
logger.info(`[RiskControlController] AI decision: ${aiDecision.requiredAction}, risk: ${aiDecision.riskLevel}`);
return res.json({
success: true,
data: aiDecision,
});
} catch (error) {
logger.error('[RiskControlController] makeDecision error:', error);
return res.status(500).json({
success: false,
error: 'DECISION_ERROR',
message: '风控AI决策失败',
});
}
}
/**
* POST /api/v1/risk/assess
*
*/
static async assessRisk(req: Request, res: Response) {
try {
const { tenantId, productId, riskType, severity, message, metadata } = req.body;
if (!tenantId || !productId || !riskType || !severity) {
return res.status(400).json({
success: false,
error: 'MISSING_REQUIRED_FIELDS',
message: '缺少必要字段',
});
}
const aiDecision = makeAIDecision({
tenantId,
operatorId: 'system',
businessType: DecisionType.RISK_CONTROL,
operationType: 'RISK_ASSESS',
targetIds: [productId],
customParams: {
riskType,
severity,
metadata,
},
});
await RiskRadarService.recordRisk({
tenantId,
productId,
type: riskType,
severity,
message,
metadata,
}, `RISK-${Date.now()}`);
logger.info(`[RiskControlController] Risk recorded: ${productId}, severity: ${severity}`);
return res.json({
success: true,
data: {
aiDecision,
riskLevel: aiDecision.riskLevel,
requiredAction: aiDecision.requiredAction,
},
});
} catch (error) {
logger.error('[RiskControlController] assessRisk error:', error);
return res.status(500).json({
success: false,
error: 'ASSESS_ERROR',
message: '风险评估失败',
});
}
}
/**
* POST /api/v1/risk/block
*
*/
static async blockTransaction(req: Request, res: Response) {
try {
const { tenantId, productId, transactionId, reason } = req.body;
if (!tenantId || !productId || !transactionId) {
return res.status(400).json({
success: false,
error: 'MISSING_REQUIRED_FIELDS',
message: '缺少必要字段',
});
}
const aiDecision = makeAIDecision({
tenantId,
operatorId: 'system',
businessType: DecisionType.RISK_CONTROL,
operationType: 'BLOCK_TRANSACTION',
targetIds: [productId, transactionId],
customParams: {
transactionId,
reason,
fraudScore: 0.95,
isObviousFraud: true,
},
});
if (aiDecision.riskLevel === RiskLevel.CRITICAL || aiDecision.riskLevel === RiskLevel.HIGH) {
logger.warn(`[RiskControlController] Transaction BLOCKED: ${transactionId}, reason: ${reason}`);
return res.status(200).json({
success: true,
data: {
action: 'BLOCKED',
transactionId,
reason,
aiDecision,
},
});
}
return res.status(200).json({
success: true,
data: {
action: 'ALLOWED',
transactionId,
aiDecision,
},
});
} catch (error) {
logger.error('[RiskControlController] blockTransaction error:', error);
return res.status(500).json({
success: false,
error: 'BLOCK_ERROR',
message: '交易拦截失败',
});
}
}
/**
* POST /api/v1/risk/scan
*
*/
static async scanRisks(req: Request, res: Response) {
try {
const { tenantId } = req.body;
if (!tenantId) {
return res.status(400).json({
success: false,
error: 'MISSING_TENANT_ID',
message: '缺少租户ID',
});
}
await RiskRadarService.performRiskScan(tenantId);
logger.info(`[RiskControlController] Risk scan completed for tenant: ${tenantId}`);
return res.json({
success: true,
data: {
message: '风险扫描完成',
tenantId,
},
});
} catch (error) {
logger.error('[RiskControlController] scanRisks error:', error);
return res.status(500).json({
success: false,
error: 'SCAN_ERROR',
message: '风险扫描失败',
});
}
}
}