using AutoMapper;
using AutoMapper.QueryableExtensions;
using EFCoreSecondLevelCacheInterceptor;
using Masuit.MyBlogs.Core.Common;
using Masuit.MyBlogs.Core.Common.Mails;
using Masuit.MyBlogs.Core.Configs;
using Masuit.MyBlogs.Core.Extensions;
using Masuit.MyBlogs.Core.Extensions.Firewall;
using Masuit.MyBlogs.Core.Infrastructure.Services.Interface;
using Masuit.MyBlogs.Core.Models.DTO;
using Masuit.MyBlogs.Core.Models.Entity;
using Masuit.MyBlogs.Core.Models.Enum;
using Masuit.MyBlogs.Core.Models.ViewModel;
using Masuit.Tools;
using Masuit.Tools.Core.Net;
using Masuit.Tools.Security;
using Masuit.Tools.Strings;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Net.Http.Headers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using SameSiteMode = Microsoft.AspNetCore.Http.SameSiteMode;
namespace Masuit.MyBlogs.Core.Controllers
{
///
/// 基本父控制器
///
[ApiExplorerSettings(IgnoreApi = true), ServiceFilter(typeof(FirewallAttribute))]
public class BaseController : Controller
{
///
/// UserInfoService
///
public IUserInfoService UserInfoService { get; set; }
///
/// MenuService
///
public IMenuService MenuService { get; set; }
///
/// LinksService
///
public ILinksService LinksService { get; set; }
public IAdvertisementService AdsService { get; set; }
public IVariablesService VariablesService { get; set; }
public UserInfoDto CurrentUser => HttpContext.Session.Get(SessionKey.UserInfo) ?? new UserInfoDto();
///
/// 客户端的真实IP
///
public string ClientIP => HttpContext.Connection.RemoteIpAddress.ToString();
///
/// 普通访客是否token合法
///
public bool VisitorTokenValid => Request.Cookies["Email"].MDString3(AppConfig.BaiduAK).Equals(Request.Cookies["FullAccessToken"]);
public IMapper Mapper { get; set; }
public MapperConfiguration MapperConfig { get; set; }
///
/// 响应数据
///
/// 数据
/// 响应状态
/// 响应消息
/// 登录状态
/// http响应码
///
public ActionResult ResultData(object data, bool success = true, string message = "", bool isLogin = true, HttpStatusCode code = HttpStatusCode.OK)
{
return Ok(new
{
IsLogin = isLogin,
Success = success,
Message = message,
Data = data,
code
});
}
protected string ReplaceVariables(string text)
{
if (string.IsNullOrEmpty(text))
{
return text;
}
var keys = Regex.Matches(text, @"\{\{[\w._-]+\}\}").Select(m => m.Value).Join(",");
if (!string.IsNullOrEmpty(keys))
{
var dic = VariablesService.GetQueryFromCache(v => keys.Contains(v.Key)).ToDictionary(v => v.Key, v => v.Value);
var template = Template.Create(text);
foreach (var (key, value) in dic)
{
template.Set(key, value);
}
return template.Render();
}
return text;
}
/// 在调用操作方法前调用。
/// 有关当前请求和操作的信息。
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
ViewBag.Desc = CommonHelper.SystemSettings["Description"];
var user = filterContext.HttpContext.Session.Get(SessionKey.UserInfo);
#if DEBUG
user = UserInfoService.GetByUsername("masuit").Mapper();
filterContext.HttpContext.Session.Set(SessionKey.UserInfo, user);
#endif
if (CommonHelper.SystemSettings.GetOrAdd("CloseSite", "false") == "true" && user?.IsAdmin != true)
{
filterContext.Result = RedirectToAction("ComingSoon", "Error");
}
if (Request.Method == HttpMethods.Post && !Request.Path.Value.Contains("get", StringComparison.InvariantCultureIgnoreCase) && CommonHelper.SystemSettings.GetOrAdd("DataReadonly", "false") == "true" && !filterContext.Filters.Any(m => m.ToString().Contains(nameof(MyAuthorizeAttribute))))
{
filterContext.Result = ResultData("网站当前处于数据写保护状态,无法提交任何数据,如有疑问请联系网站管理员!", false, "网站当前处于数据写保护状态,无法提交任何数据,如有疑问请联系网站管理员!", user != null, HttpStatusCode.BadRequest);
}
if (user == null && Request.Cookies.Any(x => x.Key == "username" || x.Key == "password")) //执行自动登录
{
string name = Request.Cookies["username"];
string pwd = Request.Cookies["password"]?.DesDecrypt(AppConfig.BaiduAK);
var userInfo = UserInfoService.Login(name, pwd);
if (userInfo != null)
{
Response.Cookies.Append("username", name, new CookieOptions
{
Expires = DateTime.Now.AddYears(1),
SameSite = SameSiteMode.Lax
});
Response.Cookies.Append("password", Request.Cookies["password"], new CookieOptions
{
Expires = DateTime.Now.AddYears(1),
SameSite = SameSiteMode.Lax
});
filterContext.HttpContext.Session.Set(SessionKey.UserInfo, userInfo);
}
}
if (ModelState.IsValid) return;
var errmsgs = ModelState.SelectMany(kv => kv.Value.Errors.Select(e => e.ErrorMessage)).ToList();
if (errmsgs.Any())
{
for (var i = 0; i < errmsgs.Count; i++)
{
errmsgs[i] = i + 1 + ". " + errmsgs[i];
}
}
filterContext.Result = ResultData(errmsgs, false, "数据校验失败,错误信息:" + errmsgs.Join(" | "), user != null, HttpStatusCode.BadRequest);
}
/// 在调用操作方法后调用。
/// 有关当前请求和操作的信息。
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext.Result is ViewResult)
{
ViewBag.menus = MenuService.GetQueryFromCache(m => m.ParentId == null && m.Status == Status.Available).OrderBy(m => m.Sort).ToList(); //菜单
var model = new PageFootViewModel //页脚
{
Links = LinksService.GetQuery(l => l.Status == Status.Available).OrderByDescending(l => l.Recommend).ThenByDescending(l => l.Loopbacks.Count).Take(30).ProjectTo(MapperConfig).Cacheable().ToList()
};
ViewBag.Footer = model;
}
}
///
/// 验证邮箱验证码
///
///
/// 邮箱地址
/// 验证码
///
internal async Task ValidateEmailCode(IMailSender mailSender, string email, string code)
{
if (CurrentUser.IsAdmin)
{
return string.Empty; ;
}
if (string.IsNullOrEmpty(Request.Cookies["ValidateKey"]))
{
if (string.IsNullOrEmpty(code))
{
return "请输入验证码!";
}
if (await RedisHelper.GetAsync("code:" + email) != code)
{
return "验证码错误!";
}
}
else if (Request.Cookies["ValidateKey"].DesDecrypt(AppConfig.BaiduAK) != email)
{
Response.Cookies.Delete("Email");
Response.Cookies.Delete("NickName");
Response.Cookies.Delete("ValidateKey");
return "邮箱验证信息已失效,请刷新页面后重新评论!";
}
if (mailSender.HasBounced(email))
{
Response.Cookies.Delete("Email");
Response.Cookies.Delete("NickName");
Response.Cookies.Delete("ValidateKey");
return "邮箱地址错误,请刷新页面后重新使用有效的邮箱地址!";
}
return string.Empty;
}
internal void WriteEmailKeyCookie(string email)
{
Response.Cookies.Append("Email", email, new CookieOptions()
{
Expires = DateTimeOffset.Now.AddYears(1),
SameSite = SameSiteMode.Lax
});
Response.Cookies.Append("ValidateKey", email.DesEncrypt(AppConfig.BaiduAK), new CookieOptions()
{
Expires = DateTimeOffset.Now.AddYears(1),
SameSite = SameSiteMode.Lax
});
}
protected void CheckPermission(List posts)
{
if (CurrentUser.IsAdmin || VisitorTokenValid || Request.IsRobot())
{
return;
}
var location = Request.Location() + "|" + string.Join("", Request.Headers.Values);
posts.RemoveAll(p =>
{
switch (p.LimitMode)
{
case RegionLimitMode.AllowRegion:
return !location.Contains(p.Regions.Split(',', StringSplitOptions.RemoveEmptyEntries));
case RegionLimitMode.ForbidRegion:
return location.Contains(p.Regions.Split(',', StringSplitOptions.RemoveEmptyEntries));
case RegionLimitMode.AllowRegionExceptForbidRegion:
if (location.Contains(p.ExceptRegions.Split(',', StringSplitOptions.RemoveEmptyEntries)))
{
return true;
}
goto case RegionLimitMode.AllowRegion;
case RegionLimitMode.ForbidRegionExceptAllowRegion:
if (location.Contains(p.ExceptRegions.Split(',', StringSplitOptions.RemoveEmptyEntries)))
{
return false;
}
goto case RegionLimitMode.ForbidRegion;
default:
return false;
}
});
}
protected void CheckPermission(Post post)
{
if (CurrentUser.IsAdmin || VisitorTokenValid || Request.IsRobot())
{
return;
}
var location = Request.Location() + "|" + string.Join("", Request.Headers.Values);
switch (post.LimitMode)
{
case RegionLimitMode.AllowRegion:
if (!location.Contains(post.Regions.Split(',', StringSplitOptions.RemoveEmptyEntries)))
{
Disallow(post);
}
break;
case RegionLimitMode.ForbidRegion:
if (location.Contains(post.Regions.Split(',', StringSplitOptions.RemoveEmptyEntries)))
{
Disallow(post);
}
break;
case RegionLimitMode.AllowRegionExceptForbidRegion:
if (location.Contains(post.ExceptRegions.Split(',', StringSplitOptions.RemoveEmptyEntries)))
{
Disallow(post);
}
goto case RegionLimitMode.AllowRegion;
case RegionLimitMode.ForbidRegionExceptAllowRegion:
if (location.Contains(post.ExceptRegions.Split(',', StringSplitOptions.RemoveEmptyEntries)))
{
break;
}
goto case RegionLimitMode.ForbidRegion;
}
}
private void Disallow(Post post)
{
RedisHelper.IncrBy("interceptCount");
RedisHelper.LPush("intercept", new IpIntercepter()
{
IP = ClientIP,
RequestUrl = $"//{Request.Host}/{post.Id}",
Referer = Request.Headers[HeaderNames.Referer],
Time = DateTime.Now,
UserAgent = Request.Headers[HeaderNames.UserAgent],
Remark = "无权限查看该文章",
Address = Request.Location(),
HttpVersion = Request.Protocol,
Headers = Request.Headers.ToJsonString()
});
throw new NotFoundException("文章未找到");
}
}
}