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>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<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="Swashbuckle.AspNetCore" Version="6.4.0" />
|
||||
<PackageReference Include="Mapster.DependencyInjection" Version="1.0.2-pre01" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Controllers\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Learn.Archives.Core\Learn.Archives.Core.csproj" />
|
||||
</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 Learn.Archives.Core.Common.Expand;
|
||||
using Mapster;
|
||||
using System.Text.Json;
|
||||
using Learn.Archives.API.Expand;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
|
|
@ -15,11 +17,16 @@ builder.Services.AddLogging(loggingBuilder =>
|
|||
loggingBuilder.SetMinimumLevel(LogLevel.Warning); // ÉèÖÃ×îСÈÕÖ¾¼¶±ðΪ Warning
|
||||
});
|
||||
|
||||
builder.Services.AddControllers()
|
||||
.AddJsonOptions(options =>
|
||||
{
|
||||
options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All);
|
||||
});
|
||||
builder.Services.AddControllers(options =>
|
||||
{
|
||||
// 全局模型赋值默认值 和 统一返回格式处理
|
||||
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.AddSwaggerGen(c =>
|
||||
{
|
||||
|
|
@ -34,19 +41,15 @@ builder.Services.AddSwaggerGen(c =>
|
|||
});
|
||||
|
||||
builder.Configuration.AddAppConfig(args);
|
||||
builder.Services.AddPermissionAuthentication();
|
||||
builder.Services.AddSqlSugarExpand();
|
||||
builder.Services.AddRedisExpand();
|
||||
builder.Services.AddCorsExpand();
|
||||
builder.Services.AddMapster();
|
||||
builder.Services.AddCorsExpand();
|
||||
builder.Services.AddLiveUserInfoExpand();
|
||||
builder.Services.AddHttpClient();
|
||||
builder.Services.AddHttpContextAccessor();
|
||||
|
||||
//异常过滤器
|
||||
builder.Services.AddControllersWithViews(options =>
|
||||
{
|
||||
options.Filters.Add(typeof(ExceptionFilter));
|
||||
});
|
||||
|
||||
|
||||
var app = builder.Build();
|
||||
|
|
@ -63,7 +66,6 @@ app.UseSqlSugarExpand();
|
|||
|
||||
app.UseAuthorization();
|
||||
|
||||
|
||||
app.MapControllers();
|
||||
|
||||
app.Run();
|
||||
|
|
|
|||
|
|
@ -8,17 +8,6 @@
|
|||
"Redis": {
|
||||
"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": {
|
||||
//"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",
|
||||
|
|
|
|||
|
|
@ -8,19 +8,20 @@
|
|||
"AllowedHosts": "*",
|
||||
"AppConfig": {
|
||||
"ID": 1, //程序唯一值
|
||||
"SimpLetex": {
|
||||
"Host": "https://server.simpletex.cn/api/",
|
||||
"AppSecret": "05ZbPfCFZgTmfd4uIqHHc9pHgYR2V8bk",
|
||||
"AppId": "GH2OXwuxSZEH5W28H61bdSzD"
|
||||
},
|
||||
"Redis": {
|
||||
"ConnectionString": "127.0.0.1:6379,password=Woshiren123,defaultDatabase=10"
|
||||
},
|
||||
"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",
|
||||
"UpdateTable": false
|
||||
},
|
||||
"AuthKey": {
|
||||
"Secret": "9FAB7AC7-F2DB-4C52-B81F-044055A34AF2",
|
||||
"Issuer": "Learn.Archive", //签发人
|
||||
"Audience": "Admin",
|
||||
"Expires": 120 // 过期时间120小时
|
||||
},
|
||||
"OtherDBArr": [
|
||||
//{
|
||||
// "ConfigId": 1001, //ResourceBank
|
||||
|
|
|
|||
|
|
@ -22,6 +22,10 @@ namespace Learn.Archives.Core.Common
|
|||
/// </summary>
|
||||
public AdminConfig Admin { get; set; } = new AdminConfig();
|
||||
/// <summary>
|
||||
/// 授权配置
|
||||
/// </summary>
|
||||
public AuthKeyConfig AuthKey { get; set; } = new AuthKeyConfig();
|
||||
/// <summary>
|
||||
/// 子系统
|
||||
/// </summary>
|
||||
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
|
||||
{
|
||||
/// <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 string _realm;
|
||||
|
||||
|
||||
|
||||
public BasicAuthMiddleware(RequestDelegate next, string realm)
|
||||
{
|
||||
_next = next;
|
||||
|
|
@ -37,7 +35,6 @@ namespace Learn.Archives.Core.Common
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
context.Response.Headers["WWW-Authenticate"] = $"Basic realm=\"{_realm}\"";
|
||||
context.Response.StatusCode = StatusCodes.Status401Unauthorized;
|
||||
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.Mvc.Abstractions" 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.Http" Version="8.0.0" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.7" />
|
||||
|
|
@ -26,10 +27,4 @@
|
|||
<PackageReference Include="SqlSugarCore" Version="5.1.4.170" />
|
||||
<PackageReference Include="UserCenter.Model" Version="1.3.9" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Model\Dto\" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@ using SqlSugar;
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Net;
|
||||
using System.Text.Json;
|
||||
using UserCenter.Model;
|
||||
using UserCenter.Model.Enum;
|
||||
using UserCenter.Model.Interface;
|
||||
|
||||
namespace Learn.Archives.Core.Model
|
||||
{
|
||||
|
|
@ -11,13 +13,8 @@ namespace Learn.Archives.Core.Model
|
|||
/// 管理员
|
||||
/// </summary>
|
||||
[SugarTable("admin")]
|
||||
public class Admin : IDB
|
||||
public class Admin : EntityBaseId,IDB
|
||||
{
|
||||
/// <summary>
|
||||
/// id
|
||||
/// </summary>
|
||||
[SugarColumn(IsPrimaryKey = true)]
|
||||
public long Id { get; set; }
|
||||
/// <summary>
|
||||
/// 账号
|
||||
/// </summary>
|
||||
|
|
@ -35,6 +32,10 @@ namespace Learn.Archives.Core.Model
|
|||
/// </summary>
|
||||
public bool Enable { get; set; }
|
||||
/// <summary>
|
||||
/// 角色id
|
||||
/// </summary>
|
||||
public long RoleId { get; set; }
|
||||
/// <summary>
|
||||
/// 创建时间
|
||||
/// </summary>
|
||||
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>
|
||||
/// </summary>
|
||||
[SugarTable("user")]
|
||||
public class User : IDB
|
||||
public class User : EntityBaseId, IDB
|
||||
{
|
||||
/// <summary>
|
||||
/// id
|
||||
/// </summary>
|
||||
[SugarColumn(IsPrimaryKey = true)]
|
||||
public long Id { get; set; }
|
||||
/// <summary>
|
||||
/// 用户中心的id
|
||||
/// <see cref="UserCenter.Model.User.Id"/>
|
||||
|
|
|
|||
Loading…
Reference in New Issue