fengling-risk-control/Fengling.RiskControl.Application/Services/RiskEvaluationService.cs

154 lines
4.9 KiB
C#

using Fengling.RiskControl.Domain.Aggregates.RiskRules;
using Fengling.RiskControl.Domain.Aggregates.RiskScores;
using Fengling.RiskControl.Domain.Repositories;
using MediatR;
namespace Fengling.RiskControl.Application.Services;
public class RiskEvaluationService : IRiskEvaluationService
{
private const int HIGH_THRESHOLD = 70;
private const int MEDIUM_THRESHOLD = 30;
private const int BLACKLIST_POINTS = 100;
private readonly IRiskRuleRepository _ruleRepository;
private readonly IRiskScoreRepository _scoreRepository;
private readonly IMediator _mediator;
public RiskEvaluationService(
IRiskRuleRepository ruleRepository,
IRiskScoreRepository scoreRepository,
IMediator mediator)
{
_ruleRepository = ruleRepository;
_scoreRepository = scoreRepository;
_mediator = mediator;
}
public async Task<RiskEvaluationResult> EvaluateRiskAsync(RiskEvaluationRequest request)
{
var rules = await _ruleRepository.GetActiveRulesAsync();
var factors = new List<RiskFactorResult>();
var totalScore = 0;
foreach (var rule in rules)
{
var factor = await EvaluateRuleAsync(rule, request);
if (factor != null)
{
factors.Add(factor);
totalScore += factor.Points;
}
}
var riskLevel = DetermineRiskLevel(totalScore);
var recommendedAction = DetermineAction(riskLevel);
var blocked = recommendedAction == RiskRuleAction.Block;
return new RiskEvaluationResult
{
TotalScore = totalScore,
Factors = factors,
RiskLevel = riskLevel,
RecommendedAction = recommendedAction,
Blocked = blocked,
Message = blocked ? "操作被风险控制系统拒绝" : "操作已通过风险评估"
};
}
public async Task<bool> IsAllowedAsync(RiskEvaluationRequest request)
{
var result = await EvaluateRiskAsync(request);
return !result.Blocked;
}
private async Task<RiskFactorResult?> EvaluateRuleAsync(RiskRule rule, RiskEvaluationRequest request)
{
return rule.RuleType switch
{
RiskRuleType.FrequencyLimit => await EvaluateFrequencyLimitAsync(rule, request),
RiskRuleType.AmountLimit => await EvaluateAmountLimitAsync(rule, request),
RiskRuleType.Blacklist => EvaluateBlacklist(rule, request),
_ => null
};
}
private async Task<RiskFactorResult?> EvaluateFrequencyLimitAsync(RiskRule rule, RiskEvaluationRequest request)
{
// Frequency limit checking requires additional repository method
// Implement when ILotteryActivityRepository.GetLotteryCountByMemberAndTypeAsync is available
return null;
}
private async Task<RiskFactorResult?> EvaluateAmountLimitAsync(RiskRule rule, RiskEvaluationRequest request)
{
var config = rule.GetConfig<AmountLimitConfig>();
if (request.Context.TryGetValue("amount", out var amountObj) && amountObj is int amount)
{
if (amount > config.MaxAmount)
{
return new RiskFactorResult
{
FactorType = "amount_limit",
Points = config.Points,
Description = $"超过金额限制: {amount}/{config.MaxAmount}",
RuleName = rule.Name
};
}
}
return null;
}
private RiskFactorResult? EvaluateBlacklist(RiskRule rule, RiskEvaluationRequest request)
{
var blacklist = rule.GetConfig<BlacklistConfig>();
if (blacklist.MemberIds.Contains(request.MemberId))
{
return new RiskFactorResult
{
FactorType = "blacklist",
Points = BLACKLIST_POINTS,
Description = "用户在黑名单中",
RuleName = rule.Name
};
}
return null;
}
private RiskLevel DetermineRiskLevel(int score)
{
return score >= HIGH_THRESHOLD ? RiskLevel.High :
score >= MEDIUM_THRESHOLD ? RiskLevel.Medium :
RiskLevel.Low;
}
private RiskRuleAction DetermineAction(RiskLevel level)
{
return level switch
{
RiskLevel.Critical => RiskRuleAction.Block,
RiskLevel.High => RiskRuleAction.RequireVerification,
RiskLevel.Medium => RiskRuleAction.FlagForReview,
_ => RiskRuleAction.Allow
};
}
}
public class FrequencyLimitConfig
{
public int MaxCount { get; set; }
public int WindowMinutes { get; set; }
public int Points { get; set; } = 30;
}
public class AmountLimitConfig
{
public int MaxAmount { get; set; }
public int Points { get; set; } = 40;
}
public class BlacklistConfig
{
public HashSet<long> MemberIds { get; set; } = new();
}