154 lines
4.9 KiB
C#
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();
|
|
}
|