This commit is contained in:
cjd
2025-11-04 21:09:16 +08:00
parent 8260e293c7
commit bb90a020dc
592 changed files with 61749 additions and 27 deletions

View File

@@ -0,0 +1,19 @@
using Autofac;
using Microsoft.AspNetCore.Mvc;
namespace DouyinApi.Filter
{
public class AutofacPropertityModuleReg : Autofac.Module
{
protected override void Load(ContainerBuilder builder)
{
// 记得要启动服务注册
// builder.Services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());
var controllerBaseType = typeof(ControllerBase);
builder.RegisterAssemblyTypes(typeof(Program).Assembly)
.Where(t => controllerBaseType.IsAssignableFrom(t) && t != controllerBaseType)
.PropertiesAutowired();
}
}
}

View File

@@ -0,0 +1,37 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using System;
using static DouyinApi.Extensions.CustomApiVersion;
namespace DouyinApi.SwaggerHelper
{
/// <summary>
/// 自定义路由 /api/{version}/[controler]/[action]
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class CustomRouteAttribute : RouteAttribute, IApiDescriptionGroupNameProvider
{
/// <summary>
/// 分组名称,是来实现接口 IApiDescriptionGroupNameProvider
/// </summary>
public string GroupName { get; set; }
/// <summary>
/// 自定义路由构造函数,继承基类路由
/// </summary>
/// <param name="actionName"></param>
public CustomRouteAttribute(string actionName = "[action]") : base("/api/{version}/[controller]/" + actionName)
{
}
/// <summary>
/// 自定义版本+路由构造函数,继承基类路由
/// </summary>
/// <param name="actionName"></param>
/// <param name="version"></param>
public CustomRouteAttribute(ApiVersions version, string actionName = "") : base($"/api/{version.ToString()}/[controller]/{actionName}")
{
GroupName = version.ToString();
}
}
}

View File

@@ -0,0 +1,56 @@
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.AspNetCore.Mvc.Filters;
using System.Linq;
using System.Threading.Tasks;
namespace DouyinApi.Filter
{
/// <summary>
/// Summary:全局路由权限公约
/// Remarks:目的是针对不同的路由,采用不同的授权过滤器
/// 如果 controller 上不加 [Authorize] 特性,默认都是 Permission 策略
/// 否则,如果想特例其他授权机制的话,需要在 controller 上带上 [Authorize]然后再action上自定义授权即可比如 [Authorize(Roles = "Admin")]
/// </summary>
public class GlobalRouteAuthorizeConvention : IApplicationModelConvention
{
public void Apply(ApplicationModel application)
{
foreach (var c in application.Controllers)
{
if (!c.Filters.Any(e => e is AuthorizeFilter))
{
// 没有写特性,就用全局的 Permission 授权
c.Filters.Add(new AuthorizeFilter(Permissions.Name));
}
else {
// 写了特性,[Authorize] 或 [AllowAnonymous] ,根据情况进行权限认证
}
}
}
}
/// <summary>
/// 全局权限过滤器【无效】
/// </summary>
public class GlobalAuthorizeFilter : AuthorizeFilter
{
public override Task OnAuthorizationAsync(AuthorizationFilterContext context)
{
if (context.Filters.Any(item => item is IAsyncAuthorizationFilter && item != this))
{
return Task.FromResult(0);
}
return base.OnAuthorizationAsync(context);
}
}
}

View File

@@ -0,0 +1,96 @@
using DouyinApi.Common;
using DouyinApi.Common.Helper;
using DouyinApi.Common.LogHelper;
using DouyinApi.Hubs;
using DouyinApi.Model;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.SignalR;
using StackExchange.Profiling;
namespace DouyinApi.Filter
{
/// <summary>
/// 全局异常错误日志
/// </summary>
public class GlobalExceptionsFilter : IExceptionFilter
{
private readonly IWebHostEnvironment _env;
private readonly IHubContext<ChatHub> _hubContext;
private readonly ILogger<GlobalExceptionsFilter> _loggerHelper;
public GlobalExceptionsFilter(IWebHostEnvironment env, ILogger<GlobalExceptionsFilter> loggerHelper, IHubContext<ChatHub> hubContext)
{
_env = env;
_loggerHelper = loggerHelper;
_hubContext = hubContext;
}
public void OnException(ExceptionContext context)
{
var json = new MessageModel<string>();
json.msg = context.Exception.Message;//错误信息
json.status = 500;//500异常
var errorAudit = "Unable to resolve service for";
if (!string.IsNullOrEmpty(json.msg) && json.msg.Contains(errorAudit))
{
json.msg = json.msg.Replace(errorAudit, $"(若新添加服务,需要重新编译项目){errorAudit}");
}
if (_env.EnvironmentName.ObjToString().Equals("Development"))
{
json.msgDev = context.Exception.StackTrace;//堆栈信息
}
var res = new ContentResult();
res.Content = JsonHelper.GetJSON<MessageModel<string>>(json);
context.Result = res;
MiniProfiler.Current.CustomTiming("Errors", json.msg);
//进行错误日志记录
_loggerHelper.LogError(json.msg + WriteLog(json.msg, context.Exception));
if (AppSettings.app(new string[] { "Middleware", "SignalRSendLog", "Enabled" }).ObjToBool())
{
_hubContext.Clients.All.SendAsync("ReceiveUpdate", LogLock.GetLogData()).Wait();
}
}
/// <summary>
/// 自定义返回格式
/// </summary>
/// <param name="throwMsg"></param>
/// <param name="ex"></param>
/// <returns></returns>
public string WriteLog(string throwMsg, Exception ex)
{
return string.Format("\r\n【自定义错误】{0} \r\n【异常类型】{1} \r\n【异常信息】{2} \r\n【堆栈调用】{3}", new object[] { throwMsg,
ex.GetType().Name, ex.Message, ex.StackTrace });
}
}
public class InternalServerErrorObjectResult : ObjectResult
{
public InternalServerErrorObjectResult(object value) : base(value)
{
StatusCode = StatusCodes.Status500InternalServerError;
}
}
//返回错误信息
public class JsonErrorResponse
{
/// <summary>
/// 生产环境的消息
/// </summary>
public string Message { get; set; }
/// <summary>
/// 开发环境的消息
/// </summary>
public string DevelopmentMessage { get; set; }
}
}

View File

@@ -0,0 +1,51 @@
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Mvc.Routing;
using System.Linq;
namespace DouyinApi.Filter
{
/// <summary>
/// 全局路由前缀公约
/// </summary>
public class GlobalRoutePrefixFilter : IApplicationModelConvention
{
private readonly AttributeRouteModel _centralPrefix;
public GlobalRoutePrefixFilter(IRouteTemplateProvider routeTemplateProvider)
{
_centralPrefix = new AttributeRouteModel(routeTemplateProvider);
}
//接口的Apply方法
public void Apply(ApplicationModel application)
{
//遍历所有的 Controller
foreach (var controller in application.Controllers)
{
// 已经标记了 RouteAttribute 的 Controller
var matchedSelectors = controller.Selectors.Where(x => x.AttributeRouteModel != null).ToList();
if (matchedSelectors.Any())
{
foreach (var selectorModel in matchedSelectors)
{
// 在 当前路由上 再 添加一个 路由前缀
selectorModel.AttributeRouteModel = AttributeRouteModel.CombineAttributeRouteModel(_centralPrefix,
selectorModel.AttributeRouteModel);
}
}
// 没有标记 RouteAttribute 的 Controller
var unmatchedSelectors = controller.Selectors.Where(x => x.AttributeRouteModel == null).ToList();
if (unmatchedSelectors.Any())
{
foreach (var selectorModel in unmatchedSelectors)
{
// 添加一个 路由前缀
selectorModel.AttributeRouteModel = _centralPrefix;
}
}
}
}
}
}

View File

@@ -0,0 +1,35 @@
using DouyinApi.IServices;
using Microsoft.AspNetCore.Mvc.Filters;
namespace DouyinApi.Filter
{
public class UseServiceDIAttribute : ActionFilterAttribute
{
protected readonly ILogger<UseServiceDIAttribute> _logger;
private readonly IBlogArticleServices _blogArticleServices;
private readonly string _name;
public UseServiceDIAttribute(ILogger<UseServiceDIAttribute> logger, IBlogArticleServices blogArticleServices, string Name = "")
{
_logger = logger;
_blogArticleServices = blogArticleServices;
_name = Name;
}
public override void OnActionExecuted(ActionExecutedContext context)
{
var dd = _blogArticleServices.Query().Result;
_logger.LogInformation("测试自定义服务特性");
Console.WriteLine(_name);
base.OnActionExecuted(context);
DeleteSubscriptionFiles();
}
private void DeleteSubscriptionFiles()
{
}
}
}

View File

@@ -0,0 +1,67 @@
using FluentValidation;
using System.Text.RegularExpressions;
namespace DouyinApi.Filter
{
public class UserRegisterVo
{
public string WxUid { get; set; }
public string Telphone { get; set; }
public string NickName { get; set; }
public string SourceType { get; set; }
public IEnumerable<CarInfo> Cars { get; set; }
}
public class CarInfo
{
public int CarCount { get; set; }
public int CarSize { get; set; }
}
public class UserRegisterVoValidator : AbstractValidator<UserRegisterVo>
{
public UserRegisterVoValidator()
{
When(x => !string.IsNullOrEmpty(x.NickName) || !string.IsNullOrEmpty(x.Telphone), () =>
{
RuleFor(x => x.NickName)
.Must(e => IsLegalName(e)).WithMessage("请填写合法的姓名,必须是汉字和字母");
RuleFor(x => x.Telphone)
.Must(e => IsLegalPhone(e)).WithMessage("请填写正确的手机号码");
RuleFor(x => x.Cars)
.NotNull().NotEmpty().WithMessage("车辆信息不正确");
RuleForEach(x => x.Cars).SetValidator(new CarInfoValidator());
});
}
public static bool IsLegalName(string username)
{
//判断用户名是否合法
const string pattern = "(^([A-Za-z]|[\u4E00-\u9FA5]){1,10}$)";
return (!string.IsNullOrEmpty(username) && Regex.IsMatch(username, pattern));
}
public static bool IsLegalPhone(string phone)
{
//判断手机号
const string pattern = "(^1\\d{10}$)";
return (!string.IsNullOrEmpty(phone) && Regex.IsMatch(phone, pattern));
}
}
public class CarInfoValidator : AbstractValidator<CarInfo>
{
public CarInfoValidator()
{
RuleFor(x => x.CarCount)
.GreaterThanOrEqualTo(0).WithMessage("车辆数量必须大于等于0")
.LessThanOrEqualTo(500).WithMessage($"存在车型数量已达上限");
RuleFor(x => x.CarSize)
.IsInEnum().WithMessage("车型不正确");
}
}
}