using CacheManager.Core; using Hangfire; using Masuit.MyBlogs.Core.Common; using Masuit.MyBlogs.Core.Configs; using Masuit.MyBlogs.Core.Extensions.Hangfire; using Masuit.Tools; using Masuit.Tools.AspNetCore.Mime; using Masuit.Tools.Logging; using Masuit.Tools.Security; using Masuit.Tools.Strings; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using System; using System.Linq; using System.Net; using System.Text; using System.Text.RegularExpressions; using System.Web; using HeaderNames = Microsoft.Net.Http.Headers.HeaderNames; namespace Masuit.MyBlogs.Core.Extensions.Firewall { public class FirewallAttribute : ActionFilterAttribute { public ICacheManager CacheManager { get; set; } public IFirewallRepoter FirewallRepoter { get; set; } /// public override void OnActionExecuting(ActionExecutingContext context) { var request = context.HttpContext.Request; var ip = context.HttpContext.Connection.RemoteIpAddress.ToString(); var tokenValid = request.Cookies["Email"].MDString3(AppConfig.BaiduAK).Equals(request.Cookies["FullAccessToken"]); if (ip.IsDenyIpAddress() && !tokenValid) { AccessDeny(ip, request, "黑名单IP地址"); context.Result = new BadRequestObjectResult("您当前所在的网络环境不支持访问本站!"); return; } if (CommonHelper.SystemSettings.GetOrAdd("FirewallEnabled", "true") == "false" || context.Filters.Any(m => m.ToString().Contains(nameof(AllowAccessFirewallAttribute))) || tokenValid) { return; } var ua = request.Headers[HeaderNames.UserAgent] + ""; var agent = UserAgent.Parse(ua); var blocked = CommonHelper.SystemSettings.GetOrAdd("UserAgentBlocked", "").Split(new[] { ',', '|' }, StringSplitOptions.RemoveEmptyEntries); if (ua.Contains(blocked)) { AccessDeny(ip, request, $"UA黑名单({agent.Browser} {agent.BrowserVersion}/{agent.Platform})"); var msg = CommonHelper.SystemSettings.GetOrAdd("UserAgentBlockedMsg", "当前浏览器不支持访问本站"); context.Result = new ContentResult() { Content = Template.Create(msg).Set("browser", agent.Browser + " " + agent.BrowserVersion).Set("os", agent.Platform).Render(), ContentType = ContentType.Html, StatusCode = 403 }; return; } if (ip.IsInDenyArea() && !tokenValid) { AccessDeny(ip, request, "访问地区限制"); throw new AccessDenyException("访问地区限制"); } if (Regex.IsMatch(request.Method, "OPTIONS|HEAD", RegexOptions.IgnoreCase) || agent.IsRobot) { return; } var times = CacheManager.AddOrUpdate("Frequency:" + ip, 1, i => i + 1, 5); CacheManager.Expire("Frequency:" + ip, ExpirationMode.Sliding, TimeSpan.FromSeconds(CommonHelper.SystemSettings.GetOrAdd("LimitIPFrequency", "60").ToInt32())); var limit = CommonHelper.SystemSettings.GetOrAdd("LimitIPRequestTimes", "90").ToInt32(); if (times <= limit) { return; } if (times > limit * 1.2) { CacheManager.Expire("Frequency:" + ip, ExpirationMode.Sliding, TimeSpan.FromMinutes(CommonHelper.SystemSettings.GetOrAdd("BanIPTimespan", "10").ToInt32())); AccessDeny(ip, request, "访问频次限制"); } throw new TempDenyException("访问频次限制"); } private async void AccessDeny(string ip, HttpRequest request, string remark) { var path = HttpUtility.UrlDecode(request.Path + request.QueryString, Encoding.UTF8); BackgroundJob.Enqueue(() => HangfireBackJob.InterceptLog(new IpIntercepter() { IP = ip, RequestUrl = HttpUtility.UrlDecode(request.Scheme + "://" + request.Host + path), Time = DateTime.Now, UserAgent = request.Headers[HeaderNames.UserAgent], Remark = remark })); var limit = CommonHelper.SystemSettings.GetOrAdd("LimitIPInterceptTimes", "30").ToInt32(); await RedisHelper.LRangeAsync("intercept", 0, -1).ContinueWith(async t => { if (t.Result.Count(x => x.IP == ip) >= limit) { LogManager.Info($"准备上报IP{ip}到{FirewallRepoter.ReporterName}"); await FirewallRepoter.ReportAsync(IPAddress.Parse(ip)).ContinueWith(_ => LogManager.Info($"访问频次限制,已上报IP{ip}至:" + FirewallRepoter.ReporterName)); } }); } } }