parent
494251c76a
commit
1e4794a879
|
|
@ -0,0 +1,52 @@
|
||||||
|
using Learn.Archives.API.Controllers.Dto;
|
||||||
|
using Learn.Archives.API.Expand;
|
||||||
|
using Learn.Archives.Core.Common;
|
||||||
|
using Learn.Archives.Core.Model;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Security.Claims;
|
||||||
|
|
||||||
|
namespace Learn.Archives.API.Controllers
|
||||||
|
{
|
||||||
|
public class AdminController : BackController<Admin>
|
||||||
|
{
|
||||||
|
readonly Repository<Admin> baseService;
|
||||||
|
public AdminController(Repository<Admin> baseService) : base(baseService)
|
||||||
|
{
|
||||||
|
this.baseService = baseService;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 后台管理员登录
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="model"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost, AllowAnonymous]
|
||||||
|
[HttpLogEnable]
|
||||||
|
public async Task<string> Login([FromBody] AdminLoginReq model)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(model.Account))
|
||||||
|
Oh.Error("登录失败,用户名不能为空");
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(model.Password))
|
||||||
|
Oh.Error("登录失败,密码不能为空");
|
||||||
|
|
||||||
|
var admin = await baseService.GetFirstAsync(x => x.Account == model.Account);
|
||||||
|
if (admin == null)
|
||||||
|
Oh.Error("登录失败,用户不存在!");
|
||||||
|
if (!admin!.Enable)
|
||||||
|
Oh.Error("登录失败,用户已锁定!");
|
||||||
|
if (admin.Password != model.Password)
|
||||||
|
Oh.Error("登录失败,密码错误");
|
||||||
|
// 获取租户信息
|
||||||
|
|
||||||
|
//获取
|
||||||
|
return JwtHelper.GetToken(AppCommon.Config.AuthKey,
|
||||||
|
[
|
||||||
|
new Claim(ClaimEnum.Role,admin.RoleId.ToString()),
|
||||||
|
new Claim(ClaimEnum.Id, admin.Id.ToString()),
|
||||||
|
new Claim(ClaimEnum.Name, admin.Name),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,156 @@
|
||||||
|
using Learn.Archives.API.Expand;
|
||||||
|
using Learn.Archives.Core.Common;
|
||||||
|
using Learn.Archives.Core.Common.Expand;
|
||||||
|
using Learn.Archives.Core.Model.Dto;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
using SqlSugar;
|
||||||
|
using UserCenter.Model.Interface;
|
||||||
|
|
||||||
|
namespace Learn.Archives.API.Controllers
|
||||||
|
{
|
||||||
|
[ApiController]
|
||||||
|
public class BaseController : ControllerBase
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 管理员接口
|
||||||
|
/// </summary>
|
||||||
|
[Authorize(AuthenticationSchemes = Authentication.Admin)]
|
||||||
|
[Route("api/[controller]/[action]")]
|
||||||
|
public abstract class BackBaseController : BaseController
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 管理员的公共接口
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
public abstract class BackController<T> : BackBaseController where T : class, IDFilter, new()
|
||||||
|
{
|
||||||
|
readonly Repository<T> _baseRepository;
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="baseService"></param>
|
||||||
|
public BackController(Repository<T> baseService) : base()
|
||||||
|
{
|
||||||
|
_baseRepository = baseService;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 详情
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpGet, Route("{id}")]
|
||||||
|
public virtual async Task<dynamic> Info(long id)
|
||||||
|
{
|
||||||
|
return await _baseRepository.GetByIdAsync(id);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 新增/修改
|
||||||
|
/// <para>id=0 时新增</para>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="model"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost, Route("edit")]
|
||||||
|
[HttpLogEnable]
|
||||||
|
public virtual async Task<bool> Edit([FromBody] T model)
|
||||||
|
{
|
||||||
|
if (model.Id == 0)
|
||||||
|
return await _baseRepository.InsertAsync(model);
|
||||||
|
else
|
||||||
|
return await _baseRepository.UpdateAsync(model);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 删除
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ids"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost, Route("delete")]
|
||||||
|
[HttpLogEnable]
|
||||||
|
public virtual async Task<bool> Del([FromBody] params long[] ids)
|
||||||
|
{
|
||||||
|
var db = _baseRepository;
|
||||||
|
int sum = 0;
|
||||||
|
if (typeof(T).IsAssignableFrom(typeof(IDeletedFilter)))
|
||||||
|
{
|
||||||
|
if(ids.Length==1)
|
||||||
|
return await db.DeleteByIdAsync(ids.First());
|
||||||
|
else
|
||||||
|
return await db.DeleteByIdsAsync(ids.Select(s=>(dynamic)s).ToArray());
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
db.Context.Ado.BeginTran();
|
||||||
|
foreach (var item in ids)
|
||||||
|
sum += await db.AsUpdateable().SetColumns("DeleteState", true)
|
||||||
|
.Where("Id=" + item).ExecuteCommandAsync();
|
||||||
|
db.Context.Ado.CommitTran();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
db.Context.Ado.RollbackTran();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 分页/全查 的基础查询函数
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="model"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
///
|
||||||
|
[NonAction]
|
||||||
|
public virtual ISugarQueryable<T> BaseQuery(QueryDto model)
|
||||||
|
{
|
||||||
|
List<IConditionalModel> where = new List<IConditionalModel>();
|
||||||
|
foreach (var item in model.Conditions)
|
||||||
|
where.Add(item);
|
||||||
|
var d = _baseRepository.AsQueryable()
|
||||||
|
.Where(where);
|
||||||
|
if ((typeof(T)).GetProperty("DeleteState") != null)
|
||||||
|
d = d.Where("DeleteState=0");
|
||||||
|
if (!string.IsNullOrEmpty(model.OrderBy))
|
||||||
|
return d.OrderByPropertyName(model.OrderBy, model.OrderByType);
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 分页查询
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="model"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost, Route("pagelist")]
|
||||||
|
public virtual async Task<dynamic> GetPageList([FromBody] QueryRequestBase model)
|
||||||
|
{
|
||||||
|
var sqlquery = BaseQuery(model);
|
||||||
|
RefAsync<int> total = 0;
|
||||||
|
var data = await sqlquery.ToPageListAsync(model.PageIndex + 1, model.PageSize, total);
|
||||||
|
return new PageResult<T>() { Data = data, Total = total };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查询下拉列表
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="model"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost, Route("querycombo")]
|
||||||
|
public virtual async Task<List<ComboModel>> QueryCombo([FromBody] QueryCombo model)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(model.ValueName) || string.IsNullOrEmpty(model.TextName))
|
||||||
|
Oh.ModelError("ValueName TextName 是必填项");
|
||||||
|
List<IConditionalModel> where = [.. model.Conditions];
|
||||||
|
var sqlquery = _baseRepository.AsQueryable().Where(where).Where("DeleteState=0");
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(model.OrderBy))
|
||||||
|
sqlquery = sqlquery.OrderByPropertyName(model.OrderBy, model.OrderByType);
|
||||||
|
var res = await sqlquery.Select<ComboModel>($"{model.TextName} as Text , {model.ValueName} as Value").ToListAsync();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
namespace Learn.Archives.API.Controllers.Dto
|
||||||
|
{
|
||||||
|
public class AdminLoginReq
|
||||||
|
{
|
||||||
|
public string Account { get; set; }
|
||||||
|
public string Password { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
using Learn.Archives.Core.Common;
|
||||||
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using System.Net;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
using System.Text;
|
||||||
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
|
using Learn.Archives.Core.Model.Dto;
|
||||||
|
using Aliyun.OSS;
|
||||||
|
|
||||||
|
namespace Learn.Archives.API.Expand
|
||||||
|
{
|
||||||
|
public static class AuthorizeExpand
|
||||||
|
{
|
||||||
|
public static IServiceCollection AddPermissionAuthentication(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddAuthentication()
|
||||||
|
.AddJwtBearer(Authentication.Admin, options =>
|
||||||
|
{
|
||||||
|
options.RequireHttpsMetadata = false;
|
||||||
|
options.TokenValidationParameters = new TokenValidationParameters
|
||||||
|
{
|
||||||
|
SaveSigninToken = false,//保存token,后台验证token是否生效(重要)
|
||||||
|
RequireExpirationTime = true, // 设置请求需要携带accesstoken的过期时间
|
||||||
|
ValidateIssuer = false,//必须验证签发人
|
||||||
|
ValidateAudience = false,//验证受众
|
||||||
|
ValidateLifetime = true,//是否验证Token有效期
|
||||||
|
ValidateIssuerSigningKey = true,//是否验证签名,不验证 会被篡改数据,不安全
|
||||||
|
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(AppCommon.Config.AuthKey.Secret)),//解密的密钥
|
||||||
|
};
|
||||||
|
options.Events = new JwtBearerEvents
|
||||||
|
{
|
||||||
|
OnAuthenticationFailed = context =>
|
||||||
|
{
|
||||||
|
context.Response.Clear();
|
||||||
|
context.Response.ContentType = "application/json";
|
||||||
|
context.Response.StatusCode = 403;
|
||||||
|
var data = new BaseReturn() { Code = 403, Message = context.Exception.Message + context.Exception?.StackTrace };
|
||||||
|
context.Response.WriteAsync(data.ToJson());
|
||||||
|
return Task.CompletedTask;
|
||||||
|
},
|
||||||
|
OnChallenge = context =>
|
||||||
|
{
|
||||||
|
context.HandleResponse();
|
||||||
|
context.Response.Clear();
|
||||||
|
context.Response.ContentType = "application/json";
|
||||||
|
context.Response.StatusCode = 403;
|
||||||
|
var data = new BaseReturn() { Code = 403, Message = context.Error + context.AuthenticateFailure?.Message };
|
||||||
|
context.Response.WriteAsync(data.ToJson());
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,255 @@
|
||||||
|
using Microsoft.AspNetCore.Mvc.Controllers;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using SqlSugar;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using System.IO;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Learn.Archives.Core.Common;
|
||||||
|
using Learn.Archives.Core.Model.Dto;
|
||||||
|
using Learn.Archives.Core.Model;
|
||||||
|
|
||||||
|
namespace Learn.Archives.API.Expand
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 使用该属性,接口对结果原样输出,不做包装
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = false)]
|
||||||
|
public class ResultIgnore : Attribute { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// http接口日志启用
|
||||||
|
/// </summary>
|
||||||
|
public class HttpLogEnable : Attribute { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Http请求过滤器
|
||||||
|
/// </summary>
|
||||||
|
public class HttpLogAttribute : ActionFilterAttribute, IAsyncExceptionFilter
|
||||||
|
{
|
||||||
|
readonly Repository<HttpLog> logService;
|
||||||
|
readonly LiveUserInfo userInfo;
|
||||||
|
readonly Stopwatch _stopwatch;//统计程序耗时
|
||||||
|
|
||||||
|
public HttpLogAttribute(Repository<HttpLog> logService, LiveUserInfo userInfo)
|
||||||
|
{
|
||||||
|
this.logService = logService;
|
||||||
|
_stopwatch = Stopwatch.StartNew();
|
||||||
|
this.userInfo = userInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 执行接口前400 处理
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context"></param>
|
||||||
|
/// <exception cref="CustomException"></exception>
|
||||||
|
public void Executing400(ActionExecutingContext context)
|
||||||
|
{
|
||||||
|
if (!context.ModelState.IsValid)
|
||||||
|
{
|
||||||
|
var errMsg = string.Join(',', context.ModelState.Values.SelectMany(s => s.Errors.Select(e => e.ErrorMessage)));
|
||||||
|
Oh.ModelError(errMsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private bool HasAttribute<T>(ActionExecutedContext context) where T : Attribute
|
||||||
|
{
|
||||||
|
if (context.ActionDescriptor is ControllerActionDescriptor descriptor)
|
||||||
|
{
|
||||||
|
// 检查方法上是否有 SkipApiResultAttribute
|
||||||
|
if (descriptor.MethodInfo.GetCustomAttributes(typeof(T), false).Any())
|
||||||
|
return true;
|
||||||
|
// 检查控制器上是否有 SkipApiResultAttribute
|
||||||
|
if (descriptor.ControllerTypeInfo.GetCustomAttributes(typeof(T), false).Any())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 接口结果格式化
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context"></param>
|
||||||
|
public BaseReturn<object>? ApiResultFormatting(ActionExecutedContext context)
|
||||||
|
{
|
||||||
|
//特殊处理:ResultIgnore,不进行返回结果包装,原样输出
|
||||||
|
if (HasAttribute<ResultIgnore>(context))
|
||||||
|
{
|
||||||
|
base.OnActionExecuted(context);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// 返回结果为JsonResult的请求进行Result包装
|
||||||
|
if (context.Exception != null)
|
||||||
|
throw context.Exception;
|
||||||
|
if (context.Result != null)
|
||||||
|
{
|
||||||
|
object? resData = null;
|
||||||
|
if (context.Result is ObjectResult objectResult)
|
||||||
|
resData = objectResult.Value;
|
||||||
|
else if (context.Result is ContentResult contentRes)
|
||||||
|
resData = contentRes.Content;
|
||||||
|
else if (context.Result is JsonResult resJ)
|
||||||
|
resData = resJ.Value;
|
||||||
|
else if (context.Result is FileResult)
|
||||||
|
return null;
|
||||||
|
var code = (context?.Result as IStatusCodeActionResult)?.StatusCode ?? 200;
|
||||||
|
var res = new BaseReturn<object>()
|
||||||
|
{
|
||||||
|
Code = code,
|
||||||
|
Data = resData,
|
||||||
|
Message = "SUCCESS"
|
||||||
|
};
|
||||||
|
context.Result = new JsonResult(res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 添加http日志信息
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context"></param>
|
||||||
|
/// <param name="result"></param>
|
||||||
|
/// <param name="e"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task AddHttpLogAsync(HttpContext context, BaseReturn<object>? result = null, Exception? e = null)
|
||||||
|
{
|
||||||
|
//特殊处理:ResultIgnore,不进行返回结果包装,原样输出
|
||||||
|
var endpoint = context.GetEndpoint();
|
||||||
|
// 直接返回原始结果,不封装
|
||||||
|
if (endpoint?.Metadata.GetMetadata<HttpLogEnable>() == null) return;
|
||||||
|
|
||||||
|
string request = null;
|
||||||
|
var logId = Yitter.IdGenerator.YitIdHelper.NextId();
|
||||||
|
if (!context.Request.Method
|
||||||
|
.Equals("GET", StringComparison.InvariantCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
context.Request.EnableBuffering();
|
||||||
|
//记录请求参数
|
||||||
|
if (context.Request.Body.CanSeek)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (context.Request.HasFormContentType && context.Request?.Form?.Files?.Count() > 0)
|
||||||
|
{
|
||||||
|
// 设置保存目录(例如:项目根目录下的Uploads文件夹)
|
||||||
|
string uploadsFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "UploadLogs", logId.ToString());
|
||||||
|
// 创建目录(如果不存在)
|
||||||
|
if (!Directory.Exists(uploadsFolder))
|
||||||
|
Directory.CreateDirectory(uploadsFolder);
|
||||||
|
foreach (var file in context.Request.Form.Files)
|
||||||
|
{
|
||||||
|
// 生成安全文件名(防止路径遍历攻击)
|
||||||
|
string uniqueFileName = Guid.NewGuid().ToString().Substring(0, 5) + "_" + Path.GetFileName(file.FileName);
|
||||||
|
string filePath = Path.Combine(uploadsFolder, uniqueFileName);
|
||||||
|
// 保存文件
|
||||||
|
using var stream = new FileStream(filePath, FileMode.Create);
|
||||||
|
await file.CopyToAsync(stream);
|
||||||
|
}
|
||||||
|
request = $"请求体包含{context.Request.Form.Files.Count()}个文件 目录 {uploadsFolder}";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context.Request.Body.Position = 0;
|
||||||
|
using var sr = new StreamReader(context.Request.Body);
|
||||||
|
request = await sr.ReadToEndAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
request = "处理请求日志时发生了错误 \r\n" + ex.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//写入队列
|
||||||
|
await logService.InsertAsync(new HttpLog
|
||||||
|
{
|
||||||
|
Id = logId,
|
||||||
|
Url = context.Request.Path + context.Request.QueryString,
|
||||||
|
Method = context.Request.Method,
|
||||||
|
Request = request,
|
||||||
|
IP = context.Connection?.RemoteIpAddress?.ToString(),
|
||||||
|
ResponseCode = result?.Code ?? -1,
|
||||||
|
Response = result != null ? JsonSerializer.Serialize(result) : null,
|
||||||
|
Authorization = context.Request.Headers.ContainsKey("Authorization")
|
||||||
|
? context.Request.Headers["Authorization"].ToString()
|
||||||
|
: string.Empty,
|
||||||
|
Exception = e?.ToString(),
|
||||||
|
ExceptionMessage = e?.Message,
|
||||||
|
AdminId = userInfo.Id ,
|
||||||
|
TotalMilliseconds = (double)_stopwatch.Elapsed.TotalMilliseconds
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 在Controller的Action执行前执行
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context"></param>
|
||||||
|
public override void OnActionExecuting(ActionExecutingContext context)
|
||||||
|
{
|
||||||
|
Executing400(context);
|
||||||
|
base.OnActionExecuting(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 在Controller的Action执行后执行
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context"></param>
|
||||||
|
public override async void OnActionExecuted(ActionExecutedContext context)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
BaseReturn<object>? res = ApiResultFormatting(context);
|
||||||
|
await AddHttpLogAsync(context.HttpContext, res);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
//添加http请求日志
|
||||||
|
|
||||||
|
base.OnActionExecuted(context);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 执行错误时
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task OnExceptionAsync(ExceptionContext context)
|
||||||
|
{
|
||||||
|
var code = -1;
|
||||||
|
var msg = context.Exception.Message;
|
||||||
|
if (context.Exception is OhException exception)
|
||||||
|
code = exception.Code;
|
||||||
|
var result = new BaseReturn()
|
||||||
|
{
|
||||||
|
Code = -1,
|
||||||
|
Message = context.Exception.Message
|
||||||
|
};
|
||||||
|
context.Result = new JsonResult(result);
|
||||||
|
await AddHttpLogAsync(context.HttpContext, null, context.Exception);
|
||||||
|
if (code == 401 || code == 403)
|
||||||
|
context.HttpContext.Response.StatusCode = code;
|
||||||
|
context.ExceptionHandled = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -5,18 +5,16 @@
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||||
|
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.18" />
|
||||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.21.0" />
|
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.21.0" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
||||||
<PackageReference Include="Mapster.DependencyInjection" Version="1.0.2-pre01" />
|
<PackageReference Include="Mapster.DependencyInjection" Version="1.0.2-pre01" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Folder Include="Controllers\" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Learn.Archives.Core\Learn.Archives.Core.csproj" />
|
<ProjectReference Include="..\Learn.Archives.Core\Learn.Archives.Core.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
@Learn.Archives.API_HostAddress = http://localhost:5199
|
|
||||||
|
|
||||||
GET {{Learn.Archives.API_HostAddress}}/weatherforecast/
|
|
||||||
Accept: application/json
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
@ -4,6 +4,8 @@ using System.Text.Encodings.Web;
|
||||||
using System.Text.Unicode;
|
using System.Text.Unicode;
|
||||||
using Learn.Archives.Core.Common.Expand;
|
using Learn.Archives.Core.Common.Expand;
|
||||||
using Mapster;
|
using Mapster;
|
||||||
|
using System.Text.Json;
|
||||||
|
using Learn.Archives.API.Expand;
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
|
|
@ -15,11 +17,16 @@ builder.Services.AddLogging(loggingBuilder =>
|
||||||
loggingBuilder.SetMinimumLevel(LogLevel.Warning); // ÉèÖÃ×îСÈÕÖ¾¼¶±ðΪ Warning
|
loggingBuilder.SetMinimumLevel(LogLevel.Warning); // ÉèÖÃ×îСÈÕÖ¾¼¶±ðΪ Warning
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.Services.AddControllers()
|
builder.Services.AddControllers(options =>
|
||||||
.AddJsonOptions(options =>
|
{
|
||||||
{
|
// 全局模型赋值默认值 和 统一返回格式处理
|
||||||
options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All);
|
options.Filters.Add<HttpLogAttribute>();
|
||||||
});
|
})
|
||||||
|
.AddJsonOptions(options =>
|
||||||
|
{
|
||||||
|
options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All);//中文转换时不使用Unicode
|
||||||
|
options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;// 默认小驼峰 null 大驼峰
|
||||||
|
});
|
||||||
builder.Services.AddEndpointsApiExplorer();
|
builder.Services.AddEndpointsApiExplorer();
|
||||||
builder.Services.AddSwaggerGen(c =>
|
builder.Services.AddSwaggerGen(c =>
|
||||||
{
|
{
|
||||||
|
|
@ -34,19 +41,15 @@ builder.Services.AddSwaggerGen(c =>
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.Configuration.AddAppConfig(args);
|
builder.Configuration.AddAppConfig(args);
|
||||||
|
builder.Services.AddPermissionAuthentication();
|
||||||
builder.Services.AddSqlSugarExpand();
|
builder.Services.AddSqlSugarExpand();
|
||||||
builder.Services.AddRedisExpand();
|
builder.Services.AddRedisExpand();
|
||||||
builder.Services.AddCorsExpand();
|
builder.Services.AddCorsExpand();
|
||||||
builder.Services.AddMapster();
|
builder.Services.AddMapster();
|
||||||
builder.Services.AddCorsExpand();
|
builder.Services.AddLiveUserInfoExpand();
|
||||||
builder.Services.AddHttpClient();
|
builder.Services.AddHttpClient();
|
||||||
builder.Services.AddHttpContextAccessor();
|
builder.Services.AddHttpContextAccessor();
|
||||||
|
|
||||||
//异常过滤器
|
|
||||||
builder.Services.AddControllersWithViews(options =>
|
|
||||||
{
|
|
||||||
options.Filters.Add(typeof(ExceptionFilter));
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
@ -63,7 +66,6 @@ app.UseSqlSugarExpand();
|
||||||
|
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
|
|
||||||
|
|
||||||
app.MapControllers();
|
app.MapControllers();
|
||||||
|
|
||||||
app.Run();
|
app.Run();
|
||||||
|
|
|
||||||
|
|
@ -8,17 +8,6 @@
|
||||||
"Redis": {
|
"Redis": {
|
||||||
"ConnectionString": "redis-external.23544.com:16379,password=poiuyt)(*&^%,defaultDatabase=3"
|
"ConnectionString": "redis-external.23544.com:16379,password=poiuyt)(*&^%,defaultDatabase=3"
|
||||||
},
|
},
|
||||||
"FFmpeg": {
|
|
||||||
" TimeSlice": 600
|
|
||||||
},
|
|
||||||
"AliyunOSS": {
|
|
||||||
"AccessKeyId": "LTAI5tDC6p9h747B7FHbgwkH",
|
|
||||||
"AccessKeySecret": "vRKgmbp1LB05LaGOjh3ZrZxbHSLYLF",
|
|
||||||
"BucketDomain": "https://learn-videoanalysis.oss-cn-chengdu.aliyuncs.com",
|
|
||||||
"Region": "cn-chengdu",
|
|
||||||
"BucketName": "learn-videoanalysis",
|
|
||||||
"EndPoint": "oss-cn-chengdu.aliyuncs.com" //上传节点
|
|
||||||
},
|
|
||||||
"DB": {
|
"DB": {
|
||||||
//"ConnectionString": "AllowLoadLocalInfile=true;Server=10.255.255.3;Port=3306;Database=learn.videoanalysis;User ID=marking;Password=qwe123!@#;CharSet=utf8mb4;pooling=true;SslMode=None",
|
//"ConnectionString": "AllowLoadLocalInfile=true;Server=10.255.255.3;Port=3306;Database=learn.videoanalysis;User ID=marking;Password=qwe123!@#;CharSet=utf8mb4;pooling=true;SslMode=None",
|
||||||
"ConnectionString": "AllowLoadLocalInfile=true;Server=rm-2vc20nd3d11g0oh6g2o.rwlb.cn-chengdu.rds.aliyuncs.com;User ID=marking;Password=poiuytPOIUYT098765)(*&^%;Port=3306;Database=learn.videoanalysis;CharSet=utf8mb4;pooling=true;SslMode=None",
|
"ConnectionString": "AllowLoadLocalInfile=true;Server=rm-2vc20nd3d11g0oh6g2o.rwlb.cn-chengdu.rds.aliyuncs.com;User ID=marking;Password=poiuytPOIUYT098765)(*&^%;Port=3306;Database=learn.videoanalysis;CharSet=utf8mb4;pooling=true;SslMode=None",
|
||||||
|
|
|
||||||
|
|
@ -8,19 +8,20 @@
|
||||||
"AllowedHosts": "*",
|
"AllowedHosts": "*",
|
||||||
"AppConfig": {
|
"AppConfig": {
|
||||||
"ID": 1, //程序唯一值
|
"ID": 1, //程序唯一值
|
||||||
"SimpLetex": {
|
|
||||||
"Host": "https://server.simpletex.cn/api/",
|
|
||||||
"AppSecret": "05ZbPfCFZgTmfd4uIqHHc9pHgYR2V8bk",
|
|
||||||
"AppId": "GH2OXwuxSZEH5W28H61bdSzD"
|
|
||||||
},
|
|
||||||
"Redis": {
|
"Redis": {
|
||||||
"ConnectionString": "127.0.0.1:6379,password=Woshiren123,defaultDatabase=10"
|
"ConnectionString": "127.0.0.1:6379,password=Woshiren123,defaultDatabase=10"
|
||||||
},
|
},
|
||||||
"DB": {
|
"DB": {
|
||||||
"ConnectionString": "AllowLoadLocalInfile=true;Server=192.168.2.9;User ID=root;Password=qwe123!@#;Port=3306;Database=learn.videoanalysis;CharSet=utf8mb4;pooling=true;SslMode=None",
|
"ConnectionString": "AllowLoadLocalInfile=true;Server=192.168.2.9;User ID=root;Password=qwe123!@#;Port=3306;Database=learn.archives;CharSet=utf8mb4;pooling=true;SslMode=None",
|
||||||
"SqlType": "MySql",
|
"SqlType": "MySql",
|
||||||
"UpdateTable": false
|
"UpdateTable": false
|
||||||
},
|
},
|
||||||
|
"AuthKey": {
|
||||||
|
"Secret": "9FAB7AC7-F2DB-4C52-B81F-044055A34AF2",
|
||||||
|
"Issuer": "Learn.Archive", //签发人
|
||||||
|
"Audience": "Admin",
|
||||||
|
"Expires": 120 // 过期时间120小时
|
||||||
|
},
|
||||||
"OtherDBArr": [
|
"OtherDBArr": [
|
||||||
//{
|
//{
|
||||||
// "ConfigId": 1001, //ResourceBank
|
// "ConfigId": 1001, //ResourceBank
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,10 @@ namespace Learn.Archives.Core.Common
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public AdminConfig Admin { get; set; } = new AdminConfig();
|
public AdminConfig Admin { get; set; } = new AdminConfig();
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
/// 授权配置
|
||||||
|
/// </summary>
|
||||||
|
public AuthKeyConfig AuthKey { get; set; } = new AuthKeyConfig();
|
||||||
|
/// <summary>
|
||||||
/// 子系统
|
/// 子系统
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public SubsystemConfig Subsystem { get; set; } = new SubsystemConfig();
|
public SubsystemConfig Subsystem { get; set; } = new SubsystemConfig();
|
||||||
|
|
@ -68,6 +72,25 @@ namespace Learn.Archives.Core.Common
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class AuthKeyConfig
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 密钥
|
||||||
|
/// </summary>
|
||||||
|
public string Secret { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 签发人
|
||||||
|
/// </summary>
|
||||||
|
public string Issuer { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 受众
|
||||||
|
/// </summary>
|
||||||
|
public string Audience { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 过期时间
|
||||||
|
/// </summary>
|
||||||
|
public int Expires { get; set; }
|
||||||
|
}
|
||||||
public class SimpLetexConfig
|
public class SimpLetexConfig
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Learn.Archives.Core.Common
|
||||||
|
{
|
||||||
|
public class Authentication
|
||||||
|
{
|
||||||
|
public const string Admin = "Admin";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -12,8 +12,6 @@ namespace Learn.Archives.Core.Common
|
||||||
private readonly RequestDelegate _next;
|
private readonly RequestDelegate _next;
|
||||||
private readonly string _realm;
|
private readonly string _realm;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public BasicAuthMiddleware(RequestDelegate next, string realm)
|
public BasicAuthMiddleware(RequestDelegate next, string realm)
|
||||||
{
|
{
|
||||||
_next = next;
|
_next = next;
|
||||||
|
|
@ -37,7 +35,6 @@ namespace Learn.Archives.Core.Common
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
context.Response.Headers["WWW-Authenticate"] = $"Basic realm=\"{_realm}\"";
|
context.Response.Headers["WWW-Authenticate"] = $"Basic realm=\"{_realm}\"";
|
||||||
context.Response.StatusCode = StatusCodes.Status401Unauthorized;
|
context.Response.StatusCode = StatusCodes.Status401Unauthorized;
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
namespace Learn.Archives.Core.Common
|
||||||
|
{
|
||||||
|
public class ClaimEnum
|
||||||
|
{
|
||||||
|
public static string TenantId => "tenant";
|
||||||
|
public static string PositionId => "position";
|
||||||
|
public static string UserId => "user";
|
||||||
|
public static string Id => "id";
|
||||||
|
public static string Role => "role";
|
||||||
|
public static string Scope => "scope";
|
||||||
|
public static string Name => "name";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.Json;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Learn.Archives.Core.Common
|
|
||||||
{
|
|
||||||
public class ExceptionFilter : IAsyncExceptionFilter
|
|
||||||
{
|
|
||||||
public ExceptionFilter()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task OnExceptionAsync(ExceptionContext context)
|
|
||||||
{
|
|
||||||
// 创建一个包含错误信息的对象
|
|
||||||
var errorObject = new
|
|
||||||
{
|
|
||||||
ErrorMessage = context.Exception.Message,
|
|
||||||
context.Exception.StackTrace,
|
|
||||||
};
|
|
||||||
// 将错误对象序列化为JSON格式
|
|
||||||
var json = errorObject.ToJson();
|
|
||||||
|
|
||||||
// 设置响应内容类型为JSON
|
|
||||||
context.HttpContext.Response.ContentType = "application/json";
|
|
||||||
// 设置状态码
|
|
||||||
context.HttpContext.Response.StatusCode = 500;
|
|
||||||
// 将JSON数据写入响应体
|
|
||||||
await context.HttpContext.Response.WriteAsync(json);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
using SqlSugar.Extensions;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Learn.Archives.Core.Common
|
||||||
|
{
|
||||||
|
public class JwtHelper
|
||||||
|
{
|
||||||
|
|
||||||
|
public static string GetToken(AuthKeyConfig jwt, params Claim[] claims)
|
||||||
|
{
|
||||||
|
return GetToken(jwt.Issuer, jwt.Audience, jwt.Secret, jwt.Expires, claims);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 生成Token
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="issuer">签发人</param>
|
||||||
|
/// <param name="audience">受众</param>
|
||||||
|
/// <param name="secreKey">密钥</param>
|
||||||
|
/// <param name="expires">过期时间(单位:小时)</param>
|
||||||
|
public static string GetToken(string issuer, string audience, string secreKey, int expires, params Claim[] claims)
|
||||||
|
{
|
||||||
|
var now = DateTime.Now;
|
||||||
|
//添加用户的信息,转成一组声明,还可以写入更多用户信息声明
|
||||||
|
var claimss = new List<Claim>
|
||||||
|
{
|
||||||
|
//JWT ID 唯一标识符
|
||||||
|
new Claim(JwtRegisteredClaimNames.Jti,Guid.NewGuid().ToString() ),
|
||||||
|
//发布时间戳 issued timestamp
|
||||||
|
new Claim(JwtRegisteredClaimNames.Iat, now.ToString()),
|
||||||
|
};
|
||||||
|
if (claims != null && claims.Length > 0)
|
||||||
|
{
|
||||||
|
claimss.AddRange(claims);
|
||||||
|
}
|
||||||
|
|
||||||
|
//下面使用 Microsoft.IdentityModel.Tokens帮助库下的类来创建JwtToken
|
||||||
|
//安全秘钥
|
||||||
|
var signingKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secreKey));
|
||||||
|
|
||||||
|
var jwt = new JwtSecurityToken(
|
||||||
|
//jwt签发人
|
||||||
|
issuer: issuer,
|
||||||
|
//jwt受众
|
||||||
|
audience: audience,
|
||||||
|
//jwt一组声明
|
||||||
|
claims: claimss,
|
||||||
|
notBefore: now,
|
||||||
|
//jwt令牌过期时间
|
||||||
|
expires: now.AddHours(value: expires),
|
||||||
|
//签名凭证: 安全密钥、签名算法
|
||||||
|
signingCredentials: new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256)
|
||||||
|
);
|
||||||
|
|
||||||
|
//生成jwt令牌(json web token)
|
||||||
|
var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);
|
||||||
|
return encodedJwt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Learn.Archives.Core.Common
|
||||||
|
{
|
||||||
|
public static class LiveUserInfoExpand
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 添加 当前作用域登录用户信息
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="services"></param>
|
||||||
|
public static void AddLiveUserInfoExpand(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddScoped<LiveUserInfo>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public class LiveUserInfo
|
||||||
|
{
|
||||||
|
|
||||||
|
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||||
|
public LiveUserInfo(IHttpContextAccessor httpContextAccessor)
|
||||||
|
{
|
||||||
|
_httpContextAccessor = httpContextAccessor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 管理员角色id
|
||||||
|
/// </summary>
|
||||||
|
public string? RoleId
|
||||||
|
{
|
||||||
|
get => _httpContextAccessor.HttpContext?.User.FindFirst(ClaimEnum.Role)?.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 管理员id
|
||||||
|
/// </summary>
|
||||||
|
public long Id
|
||||||
|
{
|
||||||
|
get => long.Parse(_httpContextAccessor.HttpContext?.User.FindFirst(ClaimEnum.Id)?.Value ?? "0");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Learn.Archives.Core.Common
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 异常抛出的拓展类
|
||||||
|
/// </summary>
|
||||||
|
public class Oh
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 抛出 异常
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
/// <param name="code"></param>
|
||||||
|
/// <exception cref="OhException"></exception>
|
||||||
|
public static void Error(string message, int code = 500)
|
||||||
|
{
|
||||||
|
throw new OhException(message, code);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 抛出 模型校验异常
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
/// <param name="code"></param>
|
||||||
|
/// <exception cref="OhException"></exception>
|
||||||
|
public static void ModelError(string message, int code = 400)
|
||||||
|
{
|
||||||
|
throw new OhException(message, code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public class OhException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 错误码
|
||||||
|
/// </summary>
|
||||||
|
public virtual int Code { get; }
|
||||||
|
public OhException(string message, int code = -1) :base(message)
|
||||||
|
{
|
||||||
|
Code= code;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -19,6 +19,7 @@
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.3.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.3.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Abstractions" Version="2.3.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.Abstractions" Version="2.3.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.3.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.3.0" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.Formatters.Json" Version="2.3.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="7.0.0" />
|
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="7.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
|
||||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.7" />
|
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.7" />
|
||||||
|
|
@ -26,10 +27,4 @@
|
||||||
<PackageReference Include="SqlSugarCore" Version="5.1.4.170" />
|
<PackageReference Include="SqlSugarCore" Version="5.1.4.170" />
|
||||||
<PackageReference Include="UserCenter.Model" Version="1.3.9" />
|
<PackageReference Include="UserCenter.Model" Version="1.3.9" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Folder Include="Model\Dto\" />
|
|
||||||
</ItemGroup>
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,9 @@ using SqlSugar;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
using UserCenter.Model;
|
||||||
using UserCenter.Model.Enum;
|
using UserCenter.Model.Enum;
|
||||||
|
using UserCenter.Model.Interface;
|
||||||
|
|
||||||
namespace Learn.Archives.Core.Model
|
namespace Learn.Archives.Core.Model
|
||||||
{
|
{
|
||||||
|
|
@ -11,13 +13,8 @@ namespace Learn.Archives.Core.Model
|
||||||
/// 管理员
|
/// 管理员
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarTable("admin")]
|
[SugarTable("admin")]
|
||||||
public class Admin : IDB
|
public class Admin : EntityBaseId,IDB
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// id
|
|
||||||
/// </summary>
|
|
||||||
[SugarColumn(IsPrimaryKey = true)]
|
|
||||||
public long Id { get; set; }
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 账号
|
/// 账号
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -35,6 +32,10 @@ namespace Learn.Archives.Core.Model
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Enable { get; set; }
|
public bool Enable { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
/// 角色id
|
||||||
|
/// </summary>
|
||||||
|
public long RoleId { get; set; }
|
||||||
|
/// <summary>
|
||||||
/// 创建时间
|
/// 创建时间
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public DateTime CreateTime { get; set; } = DateTime.Now;
|
public DateTime CreateTime { get; set; } = DateTime.Now;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Learn.Archives.Core.Model.Dto
|
||||||
|
{
|
||||||
|
public class BaseReturn
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 消息码
|
||||||
|
/// </summary>
|
||||||
|
public int Code { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 消息
|
||||||
|
/// </summary>
|
||||||
|
public string? Message { get; set; }
|
||||||
|
}
|
||||||
|
public class BaseReturn<T>
|
||||||
|
{
|
||||||
|
public required T? Data { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 消息码
|
||||||
|
/// </summary>
|
||||||
|
public int Code { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 消息
|
||||||
|
/// </summary>
|
||||||
|
public string? Message { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Learn.Archives.Core.Model.Dto
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 公共返回实体
|
||||||
|
/// </summary>
|
||||||
|
public class ComboModel
|
||||||
|
{
|
||||||
|
public ComboModel(string t, object v)
|
||||||
|
{
|
||||||
|
Text = t;
|
||||||
|
Value = v;
|
||||||
|
}
|
||||||
|
public ComboModel()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
public object Value { get; set; }
|
||||||
|
public string Text { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Learn.Archives.Core.Model.Dto
|
||||||
|
{
|
||||||
|
public class PageResult<T>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 数据
|
||||||
|
/// </summary>
|
||||||
|
public List<T> Data { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 总条数
|
||||||
|
/// </summary>
|
||||||
|
public int Total { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,75 @@
|
||||||
|
using SqlSugar;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace Learn.Archives.Core.Model.Dto
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 查询实体
|
||||||
|
/// </summary>
|
||||||
|
public partial class QueryDto
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 查询条件
|
||||||
|
/// </summary>
|
||||||
|
public List<ConditionalModel> Conditions { get; set; } = new List<ConditionalModel>();
|
||||||
|
/// <summary>
|
||||||
|
/// 排序字段名 例:【CreateTime】
|
||||||
|
/// </summary>
|
||||||
|
public string OrderBy { get; set; } = "CreateTime";
|
||||||
|
/// <summary>
|
||||||
|
/// 排序方式
|
||||||
|
/// </summary>
|
||||||
|
public OrderByType OrderByType { get; set; } = OrderByType.Desc;
|
||||||
|
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 查询请求基类
|
||||||
|
/// </summary>
|
||||||
|
public class QueryRequestBase : QueryDto
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 页面索引
|
||||||
|
/// </summary>
|
||||||
|
public int PageIndex { get; set; } = 0;
|
||||||
|
/// <summary>
|
||||||
|
/// 页面数量
|
||||||
|
/// </summary>
|
||||||
|
public int PageSize { get; set; } = 20;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 查询下拉列表
|
||||||
|
/// </summary>
|
||||||
|
public class QueryCombo : QueryDto
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 值对应属性名称
|
||||||
|
/// </summary>
|
||||||
|
[Required(ErrorMessage = "{0}是必填项")]
|
||||||
|
public string ValueName { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 文本对应属性名称
|
||||||
|
/// </summary>
|
||||||
|
[Required(ErrorMessage = "{0}是必填项")]
|
||||||
|
public string TextName { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查询导出
|
||||||
|
/// </summary>
|
||||||
|
public class QueryExport : QueryDto
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 字段转换 班级:[{1:班级}]
|
||||||
|
/// </summary>
|
||||||
|
public Dictionary<string, Dictionary<string,string>> DataSource { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 导出字段 学校:School
|
||||||
|
/// </summary>
|
||||||
|
public Dictionary<string, string> Custom { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 名称
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
using SqlSugar;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection.Metadata.Ecma335;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UserCenter.Model;
|
||||||
|
|
||||||
|
namespace Learn.Archives.Core.Model
|
||||||
|
{
|
||||||
|
///<summary>
|
||||||
|
/// 管理员角色表
|
||||||
|
///</summary>
|
||||||
|
[SugarTable("httplog")]
|
||||||
|
public partial class HttpLog : EntityBaseId
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 创建时间
|
||||||
|
/// </summary>
|
||||||
|
public DateTime CreateTime { get; set; } = DateTime.Now;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 路由
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(Length = 500)]
|
||||||
|
public string Url { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 请求方法类型
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(Length = 10)]
|
||||||
|
public string Method { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 请求来自哪个ip
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(IsNullable = true, Length = 30)]
|
||||||
|
public string IP { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 请求参数
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(IsNullable = true, ColumnDataType = "longtext")]
|
||||||
|
public string? Request { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 请求返回参数
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(IsNullable = true, ColumnDataType = "longtext")]
|
||||||
|
public string? Response { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 响应状态码
|
||||||
|
/// </summary>
|
||||||
|
public int ResponseCode { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 授权信息
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(IsNullable = true, Length = 500)]
|
||||||
|
public string? Authorization { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 异常完整信息
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(IsNullable = true, ColumnDataType = "text")]
|
||||||
|
public string Exception { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 异常信息
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(IsNullable = true, ColumnDataType = "text")]
|
||||||
|
public string? ExceptionMessage { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 管理员ID
|
||||||
|
/// </summary>
|
||||||
|
public long AdminId { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 总耗时(秒)
|
||||||
|
/// </summary>
|
||||||
|
public double TotalMilliseconds { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -13,13 +13,8 @@ namespace Learn.Archives.Core.Model
|
||||||
/// <para>数据中心拓展用户</para>
|
/// <para>数据中心拓展用户</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarTable("user")]
|
[SugarTable("user")]
|
||||||
public class User : IDB
|
public class User : EntityBaseId, IDB
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// id
|
|
||||||
/// </summary>
|
|
||||||
[SugarColumn(IsPrimaryKey = true)]
|
|
||||||
public long Id { get; set; }
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 用户中心的id
|
/// 用户中心的id
|
||||||
/// <see cref="UserCenter.Model.User.Id"/>
|
/// <see cref="UserCenter.Model.User.Id"/>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue