文章目录
前言
使用场景:使用IP黑名单防止已知恶意 IP 地址的访问,降低系统被攻击的风险。阻止来自特定 IP 地址的大量请求,可以减轻分布式拒绝服务(DDoS)攻击的影响。通过监控访问日志,可以发现异常访问行为,并将可疑 IP 地址加入黑名单进而拒绝特别IP访问网站。
使用技术:Net8.0,Redis缓存(用来存储黑名单IP)
代码配置
首先创建中间件页面
csharp
public class IpBlacklistMiddleware
{
private readonly RequestDelegate next;
private IIpBlacklistService _blacklistManager;
public IpBlacklistMiddleware(RequestDelegate next, IIpBlacklistService blacklistManager)
{
this.next = next;
_blacklistManager = blacklistManager;
}
public async Task InvokeAsync(HttpContext context)
{
//获取到用户真实IP地址
var remoteIp = context.GetUserIp()?.Replace("::ffff:", "");
// 检查 IP 是否在黑名单中
if (!string.IsNullOrEmpty(remoteIp) && _blacklistManager.IsIpBlacklisted(remoteIp))
{
// 返回 403 Forbidden 状态码
context.Response.StatusCode = StatusCodes.Status403Forbidden;
await context.Response.WriteAsync("您的IP被列入黑名单");
return;
}
await next(context);
}
}
中间件属于全局规则 ,比如请求控制器接口、服务器图片路径、css文件、js文件等等,即使静态文件请求也会进行拦截处理 。而Ip中间件的作用就是:当用户访问网站的时候,请求到达服务器后会先进入Ip中间件进行校验当前用户网络IP是否存储在Redis黑名单里面,如果是黑名单IP,直接驳回网络请求,不允许当前用户访问网站并返回403状态码 。
中间件可以在应用程序的整个生命周期中应用于所有请求,而无需在每个控制器中重复定义,所以只需要定义一遍就可以了。
其次注册服务和中间件
在 Program.cs 中注册 Redis 服务和中间件:
csharp
var builder = WebApplication.CreateBuilder(args);
//reids配置
builder.Services.AddSingleton(new RedisService(builder.Configuration["Redis:ConnectionString"]));
builder.Services.AddControllers();
var app = builder.Build();
// Ip中间件
app.UseMiddleware<IpBlacklistMiddleware>();
app.UseAuthorization();
app.MapControllers();
app.Run();
这时候在网站运行的时候,就已经开启了中间件全局拦截。
然后再填写Redis的配置
在appsettings.json里面填写redis的连接配置:
csharp
"RedisConn": "127.0.0.1,Password=111111,SyncTimeout=15000", //redis连接字符串
在redis公共方法里面进行配置:
csharp
public RedisCacheService()
{
var csredis = new CSRedisClient(AppSetting.RedisConnectionString);
RedisHelper.Initialization(csredis);
}
csharp
public class IpBlacklistService : IIpBlacklistService
{
private RedisCacheService _redisCacheService;
private const string BlacklistKey = "ip_blacklist";
public IpBlacklistService(RedisCacheService redisCacheService)
{
_redisCacheService = redisCacheService;
}
//添加 IP 到黑名单
public bool AddIp(string ip)
{
if (!string.IsNullOrWhiteSpace(ip))
{
_redisCacheService.SAddToSet(BlacklistKey, ip);
return true;
}
return false;
}
//检查 IP 是否在黑名单中
public bool IsIpBlacklisted(string ip)
{
if (string.IsNullOrWhiteSpace(ip))
{
return false;
}
// 使用 RedisCacheService 检查 IP 是否在黑名单中
return _redisCacheService.Exists(BlacklistKey) &&
_redisCacheService.IsMember(BlacklistKey, ip);
}
//从黑名单中移除 IP
public bool RemoveIp(string ip)
{
if (!string.IsNullOrWhiteSpace(ip))
{
_redisCacheService.RemoveFromSet(BlacklistKey, ip);
return true;
}
return false;
}
}
然后在控制器中编写Api
csharp
[JWTAuthorize]
[Route("/api/IpBlack")]
public class IpBlackController : Controller
{
private readonly IIpBlacklistService _ipBlacklistService;
public IpBlackController(IIpBlacklistService ipBlacklistService)
{
_ipBlacklistService = ipBlacklistService;
}
// 添加 IP 到黑名单
[HttpPost, Route("Add"), AllowAnonymous]
public ActionResult AddIp(string ip)
{
if (string.IsNullOrWhiteSpace(ip))
{
return Json(false);
}
try
{
var result = _ipBlacklistService.AddIp(ip);
return Json(new { code = 200, status=result });
}
catch (Exception ex)
{
return Json(new { code = 400, status = false });
}
}
[HttpPost("Remove")]
//[ApiActionPermission(ActionRolePermission.SuperAdmin)]
[AllowAnonymous]
public ActionResult RemoveIp([FromBody] string ip)
{
if (string.IsNullOrWhiteSpace(ip))
{
return Json(false);
}
var result = _ipBlacklistService.RemoveIp(ip);
return Json(result);
}
注意:项目使用了Jwttoken进行身份验证,但是ip黑名单的接口不需要身份验证,所以在接口头部增加AllowAnonymous取消身份验证。
到此代码开发部分算是完成。
下面可以增加一些测试:使用Postman增加黑名单Ip
然后在redis里面就可以看到已经存在当前Ip值。
最后使用Jmeter测试工具进行对接口添加到Redis的数据性能测试。
并发生成5000条数据,没有问题,校验redis并发添加问题。
技术细节
在本地开发阶段,为了顺利进行项目开发,以下工具和配置是必需的:
1.Redis 客户端:
在本地电脑上安装 Redis 客户端,例如 RedisDesktopManager。这样可以方便地管理和查看 Redis 数据库中的数据。
注意:如果项目中配置的 Redis 地址指向本地,但本地未安装 Redis,将会导致连接错误。
2.性能测试:
使用 JMeter 软件进行性能测试,可以模拟大量用户请求,以评估系统的响应能力和稳定性。
3.接口测试:
使用 Postman 进行接口测试,方便地发送请求并查看返回结果,确保 API 的正确性和性能。
4.IP 校验:
在校验用户 IP 时,需要注意获取到的 IP 地址可能是 IPv6 格式。在这种情况下,需要去除前缀 ::ffff:,以便进行准确的校验。
小结
代码不算多,也容易理解,主要是各种工具的配合使用需要慢慢去配置,这个需要花费一些时间来熟悉。