2021-05-26 乐帮网
netcore
本教程只是抛砖引玉,展示了如何利用中间件来拦截指定的用户。下面开始我们的程序。首先建立一个空的ASP .Net Core MVC程序 。使用默认配置就可以了,接着我们写一个中间件,实现的功能是:记录所有用户10秒内访问的时间点儿,如果在10秒内访问次数超过了10次那么我们就认为此用户可能 为程序 其并不真实的用户。当然这里只是描述成这样的功能,你可以根据自己的实际情况扩展,例如黑名单制度,例如限定访问的资源有什么特征时才启用此规则。除此外我们还利用IP来判断是否同一个用户。
新建一个中间件类FrequencyMiddleware,具体代码如下:
public class FrequencyMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<FrequencyMiddleware> _logger;
private readonly IConfiguration _configuration;
public FrequencyMiddleware(RequestDelegate next, ILogger<FrequencyMiddleware> logger, IConfiguration configuration)
{
_next = next;
_logger = logger;
_configuration = configuration;
}
public async Task Invoke(HttpContext context)
{
try
{
HttpRequest request = context.Request;
string userIP;
if (!string.IsNullOrEmpty(request.Headers["HTTP_X_FORWARDED_FOR"]))
userIP = request.Headers["REMOTE_ADDR"];
else if (!string.IsNullOrEmpty(request.Headers["HTTP_X_FORWARDED_FOR"]))
userIP = request.Headers["HTTP_X_FORWARDED_FOR"];
else if (!string.IsNullOrEmpty(request.Headers["X-Real-IP"]))
userIP = request.Headers["X-Real-IP"];
else
userIP = request.HttpContext.Connection.RemoteIpAddress.ToString();
if (string.IsNullOrEmpty(userIP))//|| !userIP.Contains(".")
{
await _next.Invoke(context);
return;
}
string url = string.Concat(request.Scheme, "://", request.Host, request.Path, request.QueryString);
string path = request.Path.ToString().ToLower();
NoteModel blockModel = CacheHelper.GetCache<NoteModel>(userIP);
if (blockModel == null)
blockModel = new NoteModel();
blockModel.StepUp();
CacheHelper.SetCache(userIP, blockModel, 10);
if (blockModel.Count() >= 10)
{
await context.Response.WriteAsync("Unauthorized access");
return;
}
//var features = context.Features;
}
catch (Exception e)
{
_logger.LogError(e, "FrequencyMiddleware Error ");
}
await _next.Invoke(context);
}
}
其中用到我自定义实体类NoteModel,代码如下 :
public class NoteModel
{
private IList<DateTime> Records { get; set; }
private readonly int MAXCOUNT = 10;
public int Count()
{
int res = 0;
foreach (var d in Records)
{
if (d > DateTime.Now.AddSeconds(-MAXCOUNT))
{
res++;
}
}
return res;
}
public void StepUp()
{
if (Records == null)
{
Records = new List<DateTime>();
}
Records.Add(DateTime.Now); ;
}
}
还用到了Cach类,我封装如下:
public class CacheHelper
{
private static readonly Object locker = new object();
private static MemoryCache memoryCache = new MemoryCache(new MemoryCacheOptions() { });
/// <summary>
/// 获取数据缓存
/// </summary>
/// <param name="key">键</param>
public static T GetCache<T>(string key)
{
T t = memoryCache.Get<T>(key);
return t;
}
public static bool IsExists(string key)
{
object res;
memoryCache.TryGetValue(key, out res);
if (res == null)
return false;
else
return true;
}
/// <summary>
/// 获取缓存
/// </summary>
/// <typeparam name="T">T</typeparam>
/// <param name="key">键</param>
/// <param name="cachePopulate">定义获取</param>
/// <param name="slidingExpiration">过期时间</param>
/// <param name="absoluteExpiration">过期时间</param>
/// <returns>T</returns>
public static T GetCache<T>(string key, Func<T> cachePopulate, TimeSpan? slidingExpiration = null, DateTimeOffset? absoluteExpiration = null)
{
if (String.IsNullOrWhiteSpace(key)) throw new ArgumentException("Invalid cache key");
if (cachePopulate == null) throw new ArgumentNullException("cachePopulate");
if (slidingExpiration == null && absoluteExpiration == null) throw new ArgumentException("Either a sliding expiration or absolute must be provided");
T res;
memoryCache.TryGetValue<T>(key, out res);
if (res == null)
{
lock (locker)
{
memoryCache.TryGetValue<T>(key, out res);
if (res == null)
{
res = cachePopulate();
if (slidingExpiration != null)
memoryCache.Set<T>(key, res, slidingExpiration.Value);
else if (absoluteExpiration != null)
memoryCache.Set<T>(key, res, absoluteExpiration.Value);
}
}
}
return res;
}
/// <summary>
/// 设置数据缓存
/// </summary>
/// <param name="cacheKey">cacheKey</param>
/// <param name="objObject">objObject</param>
/// <param name="timeout">Seconds</param>
public static void SetCache(string cacheKey, object objObject, int timeout = 7200)
{
try
{
if (objObject == null) return;
memoryCache.Set(cacheKey, objObject, TimeSpan.FromSeconds(timeout));
}
catch (Exception)
{
//throw;
}
}
/// <summary>
/// 移除指定数据缓存
/// </summary>
public static void RemoveAllCache(string cacheKey)
{
memoryCache.Remove(cacheKey);
}
}
还有就是中间件的扩展方法,我定义如下:
public static class FrequencyExtensions
{
/// <summary>
/// Demo 中间件 lebang2020.cn
/// </summary>
/// <param name="builder">builder</param>
/// <returns>IApplicationBuilder</returns>
public static IApplicationBuilder UseFrequencyMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<FrequencyMiddleware>();
}
}
最后就是启用中间件了,我们在Startup配置启用中间件
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseFrequencyMiddleware();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
我们可以按F5进行测试,然后就是在浏览器连接刷新页面10秒内刷新多次。最终会看到我们的访问被 禁止了,而过了30秒后又会自动恢复正常访问如下图。
这里提供百度网盘源码链接:https://pan.baidu.com/s/1rxpleoytLuc-yX78d1miUA
关注我的微信公众号
在公众号里留言交流
投稿邮箱:1052839972@qq.com
庭院深深深几许?杨柳堆烟,帘幕无重数。
玉勒雕鞍游冶处,楼高不见章台路。
雨横风狂三月暮。门掩黄昏,无计留春住。
泪眼问花花不语,乱红飞过秋千去。
如果感觉对您有帮助
欢迎向作者提供捐赠
这将是创作的最大动力