|
using EzCoreNet.Redis;
|
using Furion;
|
using Furion.FriendlyException;
|
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc.Filters;
|
using System;
|
using System.Collections.Generic;
|
using System.IO;
|
using System.Linq;
|
using System.Security.Claims;
|
using System.Text;
|
using System.Threading.Tasks;
|
|
namespace Cylsg.Filter
|
{
|
|
public enum Limttype
|
{
|
/// <summary>
|
///共用限流
|
/// </summary>
|
All,
|
/// <summary>
|
/// 用户级限流
|
/// </summary>
|
User
|
}
|
|
/// <summary>
|
/// 限流
|
/// </summary>
|
|
public class LimitFilterAttribute : Attribute,IAsyncActionFilter
|
{
|
|
/// <summary>
|
/// redis限流文件夹名称
|
/// </summary>
|
private const string DirKey = "UserRateLimit:";
|
/// <summary>
|
/// 限流发生时 返回的提示
|
/// </summary>
|
public string ResponseMeg { get; set; } = "请不要在短时间内重复访问该资源";
|
|
/// <summary>
|
/// 限流时长 单位秒 默认为1秒
|
/// </summary>
|
public int timespan { get; set; } = 1;
|
/// <summary>
|
/// 限流次数 默认为1次
|
/// </summary>
|
public int InCount { get; set; } = 1;
|
|
/// <summary>
|
/// 默认为用户级
|
/// </summary>
|
public Limttype LimiType { get; set; }= Limttype.All;
|
|
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
|
{
|
var redisHelper = App.GetService<IEzCoreNetRedisService>();
|
if(redisHelper == null)
|
{
|
throw Oops.Oh("内存服务异常,请求终止");
|
}
|
|
var path = context.HttpContext?.Request?.Path.Value;
|
if (string.IsNullOrEmpty(path))
|
{
|
//非API控制器,直接放行 没有找到路径
|
await next.Invoke();
|
return;
|
}
|
string key = "";
|
if (LimiType == Limttype.User)
|
{
|
if (App.User?.FindFirstValue("UserID") == null)
|
{
|
//没有用户直接放行
|
await next.Invoke();
|
return;
|
}
|
|
key = $"{DirKey}:{path}:{App.User?.FindFirstValue("UserID")}";
|
}
|
else
|
if(LimiType == Limttype.All)
|
{
|
key = $"{DirKey}:{path}:All";
|
}
|
else
|
{
|
await next.Invoke();
|
return;
|
}
|
|
|
long? count = redisHelper.Get<int>(key);
|
if (count == null || count == 0)
|
{
|
redisHelper.Incrby(key);
|
redisHelper.SetTtl(key, timespan);
|
}
|
else
|
if (count >= (InCount))
|
{
|
throw Oops.Oh(ResponseMeg);
|
|
}
|
else
|
{
|
redisHelper.Incrby(key);
|
}
|
|
await next.Invoke();
|
|
|
}
|
}
|
}
|