对接fake simple admin

This commit is contained in:
xiaolipro 2025-12-25 18:06:35 +08:00
parent e19e1e6142
commit 4c200cd1ff
11 changed files with 99 additions and 425 deletions

View File

@ -11,17 +11,20 @@ public class JWTEncryption
public static TokenValidationParameters CreateTokenValidationParameters(
JWTSettingsOptions jwtSettings)
{
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.SecretKey));
return new TokenValidationParameters()
{
ValidateIssuerSigningKey = jwtSettings.ValidateIssuerSigningKey,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.IssuerSigningKey)),
ValidateIssuer = jwtSettings.ValidateIssuer,
ValidIssuer = jwtSettings.ValidIssuer,
ValidateAudience = jwtSettings.ValidateAudience,
ValidAudience = jwtSettings.ValidAudience,
ValidateLifetime = jwtSettings.ValidateLifetime,
ClockSkew = TimeSpan.FromSeconds(jwtSettings.ClockSkew),
RequireExpirationTime = jwtSettings.RequireExpirationTime
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = jwtSettings.Issuer,
ValidAudience = jwtSettings.Audience,
IssuerSigningKey = key,
ClockSkew = TimeSpan.FromSeconds(jwtSettings.ClockSkewMinutes),
// 验证过期时间
RequireExpirationTime = true
};
}
}

View File

@ -4,36 +4,38 @@ namespace TrackCenter.Api;
/// <summary>Jwt 配置</summary>
public sealed class JWTSettingsOptions
{
/// <summary>验证签发方密钥</summary>
public bool ValidateIssuerSigningKey { get; set; }
/// <summary>
/// 配置节名称
/// </summary>
public static string SectionName = "JwtSettings";
/// <summary>签发方密钥</summary>
public string IssuerSigningKey { get; set; }
/// <summary>
/// 密钥(至少32位字符)
/// </summary>
public string SecretKey { get; set; } = "YourSuperSecretKeyThatIsAtLeast32CharactersLong!";
/// <summary>验证签发方</summary>
public bool ValidateIssuer { get; set; }
/// <summary>
/// 签发者
/// </summary>
public string Issuer { get; set; } = "SimpleAdmin";
/// <summary>签发方</summary>
public string ValidIssuer { get; set; }
/// <summary>
/// 受众
/// </summary>
public string Audience { get; set; } = "SimpleAdminClient";
/// <summary>验证签收方</summary>
public bool ValidateAudience { get; set; }
/// <summary>
/// Access Token 过期时间(分钟)
/// </summary>
public int ExpiryInMinutes { get; set; } = 60;
/// <summary>签收方</summary>
public string ValidAudience { get; set; }
/// <summary>
/// Refresh Token 过期时间(天)
/// </summary>
public int RefreshExpiryInDays { get; set; } = 7;
/// <summary>验证生存期</summary>
public bool ValidateLifetime { get; set; }
/// <summary>过期时间容错值,解决服务器端时间不同步问题(秒)</summary>
public long ClockSkew { get; set; }
/// <summary>过期时间(分钟)</summary>
public long ExpiredTime { get; set; }
/// <summary>加密算法</summary>
public string Algorithm { get; set; }
/// <summary>验证过期时间,设置 false 永不过期</summary>
public bool RequireExpirationTime { get; set; } = true;
/// <summary>
/// 时钟偏移(分钟),用于处理服务器时间差异
/// </summary>
public int ClockSkewMinutes { get; set; } = 5;
}

View File

@ -18,7 +18,7 @@
<ItemGroup>
<ProjectReference Include="..\TrackCenter.Application\TrackCenter.Application.csproj" />
<ProjectReference Include="..\TrackCenter.Repository\TrackCenter.Repository.csproj" />
<PackageReference Include="Fake.Autofac" Version="8.0.0-preview18" />
<PackageReference Include="Fake.Autofac" Version="8.0.0-preview19" />
<PackageReference Include="Serilog.AspNetCore" Version="9.0.0" />
<PackageReference Include="Serilog.Sinks.Elasticsearch" Version="10.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />

View File

@ -1,8 +1,10 @@
using Fake.AspNetCore;
using Fake.AspNetCore.Auditing;
using Fake.AspNetCore.Mvc;
using Fake.AspNetCore.Mvc.Conventions;
using Fake.Autofac;
using Fake.Modularity;
using Fake.Security.Claims;
using FluentValidation.AspNetCore;
using Hangfire;
using Microsoft.AspNetCore.Authorization;
@ -28,14 +30,19 @@ public class TrackCenterApiModule : FakeModule
{
private const string DefaultCorsPolicyName = "default";
public override void PreConfigureServices(ServiceConfigurationContext context)
{
FakeClaimTypes.UserId = "mapId";
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
var services = context.Services;
var configuration = context.Services.GetConfiguration();
services.Configure<ApplicationService2ControllerOptions>(options =>
services.Configure<FakeAspNetCoreMvcOptions>(options =>
{
options.ScanApplicationServices<TrackCenterApplicationModule>();
options.ApplicationServices2Controller<TrackCenterApplicationModule>();
});
// 配置签名验证选项
@ -76,10 +83,8 @@ public class TrackCenterApiModule : FakeModule
}
});
})
.AddFakeExceptionFilter()
.AddFakeValidationActionFilter()
.AddFakeAspNetCoreAuditing()
.AddFakeUnitOfWorkActionFilter();
.AddFakeAspNetCoreAuditing();
services.AddFluentValidationAutoValidation().AddFluentValidationClientsideAdapters();
var otelOptions = new OTelOptions()

View File

@ -176,17 +176,12 @@
"EnableSql": true,//启动SQL 默认 true
"EnableSqlParameters": true //启动SQL参数,默认 false
},
"JWTSettings": {
"ValidateIssuerSigningKey": true, // 是否验证密钥,bool 类型,默认true
"IssuerSigningKey": "3c1cbc3f546eda35168c3aa3cb91780fbe703f0996c1d133ea96dc85c70bbc0a", // 密钥,string 类型,必须是复杂密钥,长度大于16
"ValidateIssuer": true, // 是否验证签发方,bool 类型,默认true
"ValidIssuer": "SimpleAdmin", // 签发方,string 类型
"ValidateAudience": true, // 是否验证签收方,bool 类型,默认true
"ValidAudience": "SimpleAdmin", // 签收方,string 类型
"ValidateLifetime": true, // 是否验证过期时间,bool 类型,默认true,建议true
"ExpiredTime": 50000, // 过期时间,long 类型,单位分钟,默认20分钟
"ClockSkew": 10, // 过期时间容错值,long 类型,单位秒,默认5秒
"Algorithm": "HS256" // 加密算法,string 类型,默认 HS256
"JwtSettings": {
"SecretKey": "YourSuperSecretKeyThatIsAtLeast32CharactersLong!",
"Issuer": "SimpleAdmin",
"Audience": "SimpleAdminClient",
"ExpiryInMinutes": 60,
"RefreshExpiryInDays": 7
},
"SignatureValidation": {
"Enabled": true, // 是否启用签名验证

View File

@ -8,9 +8,9 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Fake.AspNetCore" Version="8.0.0-preview18" />
<PackageReference Include="Fake.EventBus.RabbitMQ" Version="8.0.0-preview18" />
<PackageReference Include="Fake.ObjectMapping.AutoMapper" Version="8.0.0-preview18" />
<PackageReference Include="Fake.AspNetCore" Version="8.0.0-preview19" />
<PackageReference Include="Fake.EventBus.RabbitMQ" Version="8.0.0-preview19" />
<PackageReference Include="Fake.ObjectMapping.AutoMapper" Version="8.0.0-preview19" />
<PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.14.1" />
<PackageReference Include="Confluent.Kafka" Version="2.10.0" />

View File

@ -9,11 +9,11 @@
<ItemGroup>
<PackageReference Include="NEST" Version="7.17.5" />
<PackageReference Include="Fake.SqlSugarCore" Version="8.0.0-preview18" />
<PackageReference Include="Fake.SqlSugarCore" Version="8.0.0-preview19" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Serilog" Version="4.2.3" />
<PackageReference Include="Fake.DomainDrivenDesign" Version="8.0.0-preview18" />
<PackageReference Include="Serilog" Version="4.3.0" />
<PackageReference Include="Fake.DomainDrivenDesign" Version="8.0.0-preview19" />
</ItemGroup>
</Project>

View File

@ -1,395 +1,64 @@
using Fake.Domain.Entities.Auditing;
namespace TrackCenter.Domain.VEntities;
/// <summary>
/// 服务商主表
/// 用户视图实体
/// </summary>
[SugarTable("v_user")]
public class VUserEntity
public class VUserEntity : FullAuditedAggregateRoot<Guid, Guid>
{
/// <summary>
/// Desc:Id
/// Default:
/// Nullable:False
/// 主键
/// </summary>
[SugarColumn(IsPrimaryKey = true)]
public long Id { get; set; }
[SugarColumn(ColumnName = "Id", IsPrimaryKey = true)]
public Guid Id { get; set; }
/// <summary>
/// Desc:头像
/// Default:
/// Nullable:True
/// 用户名
/// </summary>
public string? Avatar { get; set; }
[SugarColumn(ColumnName = "Name")]
public string Name { get; set; }
/// <summary>
/// Desc:签名
/// Default:
/// Nullable:True
/// 账号
/// </summary>
public string? Signature { get; set; }
[SugarColumn(ColumnName = "Account")]
public string Account { get; set; }
/// <summary>
/// Desc:账号
/// Default:
/// Nullable:False
/// 加密密码
/// </summary>
public string Account { get; set; } = null!;
[SugarColumn(ColumnName = "EncryptPassword_Password")]
public string EncryptPasswordPassword { get; set; }
/// <summary>
/// Desc:密码
/// Default:
/// Nullable:False
/// 密码盐值
/// </summary>
public string Password { get; set; } = null!;
[SugarColumn(ColumnName = "EncryptPassword_Salt")]
public string EncryptPasswordSalt { get; set; }
/// <summary>
/// Desc:姓名
/// Default:
/// Nullable:True
/// </summary>
public string? Name { get; set; }
/// <summary>
/// Desc:昵称
/// Default:
/// Nullable:True
/// </summary>
public string? Nickname { get; set; }
/// <summary>
/// Desc:性别
/// Default:
/// Nullable:True
/// </summary>
public string? Gender { get; set; }
/// <summary>
/// Desc:出生日期
/// Default:
/// Nullable:True
/// </summary>
public string? Birthday { get; set; }
/// <summary>
/// Desc:民族
/// Default:
/// Nullable:True
/// </summary>
public string? Nation { get; set; }
/// <summary>
/// Desc:籍贯
/// Default:
/// Nullable:True
/// </summary>
public string? NativePlace { get; set; }
/// <summary>
/// Desc:家庭住址
/// Default:
/// Nullable:True
/// </summary>
public string? HomeAddress { get; set; }
/// <summary>
/// Desc:通信地址
/// Default:
/// Nullable:True
/// </summary>
public string? MailingAddress { get; set; }
/// <summary>
/// Desc:证件类型
/// Default:
/// Nullable:True
/// </summary>
public string? IdCardType { get; set; }
/// <summary>
/// Desc:证件号码
/// Default:
/// Nullable:True
/// </summary>
public string? IdCardNumber { get; set; }
/// <summary>
/// Desc:文化程度
/// Default:
/// Nullable:True
/// </summary>
public string? CultureLevel { get; set; }
/// <summary>
/// Desc:政治面貌
/// Default:
/// Nullable:True
/// </summary>
public string? PoliticalOutlook { get; set; }
/// <summary>
/// Desc:毕业院校
/// Default:
/// Nullable:True
/// </summary>
public string? College { get; set; }
/// <summary>
/// Desc:学历
/// Default:
/// Nullable:True
/// </summary>
public string? Education { get; set; }
/// <summary>
/// Desc:学制
/// Default:
/// Nullable:True
/// </summary>
public string? EduLength { get; set; }
/// <summary>
/// Desc:学位
/// Default:
/// Nullable:True
/// </summary>
public string? Degree { get; set; }
/// <summary>
/// Desc:手机
/// Default:
/// Nullable:True
/// </summary>
public string? Phone { get; set; }
/// <summary>
/// Desc:邮箱
/// Default:
/// Nullable:True
/// 邮箱
/// </summary>
[SugarColumn(ColumnName = "Email")]
public string? Email { get; set; }
/// <summary>
/// Desc:家庭电话
/// Default:
/// Nullable:True
/// 头像
/// </summary>
public string? HomeTel { get; set; }
[SugarColumn(ColumnName = "Avatar")]
public string? Avatar { get; set; }
/// <summary>
/// Desc:办公电话
/// Default:
/// Nullable:True
/// 所属组织ID
/// </summary>
public string? OfficeTel { get; set; }
[SugarColumn(ColumnName = "OrganizationId")]
public Guid? OrganizationId { get; set; }
/// <summary>
/// Desc:紧急联系人
/// Default:
/// Nullable:True
/// 用户ID(用于映射)
/// </summary>
public string? EmergencyContact { get; set; }
/// <summary>
/// Desc:紧急联系人电话
/// Default:
/// Nullable:True
/// </summary>
public string? EmergencyPhone { get; set; }
/// <summary>
/// Desc:紧急联系人地址
/// Default:
/// Nullable:True
/// </summary>
public string? EmergencyAddress { get; set; }
/// <summary>
/// Desc:员工编号
/// Default:
/// Nullable:True
/// </summary>
public string? EmpNo { get; set; }
/// <summary>
/// Desc:入职日期
/// Default:
/// Nullable:True
/// </summary>
public string? EntryDate { get; set; }
/// <summary>
/// Desc:机构id
/// Default:
/// Nullable:False
/// </summary>
public long OrgId { get; set; }
/// <summary>
/// Desc:职位id
/// Default:
/// Nullable:False
/// </summary>
public long PositionId { get; set; }
/// <summary>
/// Desc:职级
/// Default:
/// Nullable:True
/// </summary>
public string? PositionLevel { get; set; }
/// <summary>
/// Desc:主管id
/// Default:
/// Nullable:True
/// </summary>
public long? DirectorId { get; set; }
/// <summary>
/// Desc:密码提醒修改时间
/// Default:
/// Nullable:True
/// </summary>
public DateTime? PwdRemindUpdateTime { get; set; }
/// <summary>
/// Desc:上次登录ip
/// Default:
/// Nullable:True
/// </summary>
public string? LastLoginIp { get; set; }
/// <summary>
/// Desc:上次登录地点
/// Default:
/// Nullable:True
/// </summary>
public string? LastLoginAddress { get; set; }
/// <summary>
/// Desc:上次登录时间
/// Default:
/// Nullable:True
/// </summary>
public DateTime? LastLoginTime { get; set; }
/// <summary>
/// Desc:上次登录设备
/// Default:
/// Nullable:True
/// </summary>
public string? LastLoginDevice { get; set; }
/// <summary>
/// Desc:最新登录ip
/// Default:
/// Nullable:True
/// </summary>
public string? LatestLoginIp { get; set; }
/// <summary>
/// Desc:最新登录地点
/// Default:
/// Nullable:True
/// </summary>
public string? LatestLoginAddress { get; set; }
/// <summary>
/// Desc:最新登录时间
/// Default:
/// Nullable:True
/// </summary>
public DateTime? LatestLoginTime { get; set; }
/// <summary>
/// Desc:最新登录设备
/// Default:
/// Nullable:True
/// </summary>
public string? LatestLoginDevice { get; set; }
/// <summary>
/// Desc:排序码
/// Default:
/// Nullable:True
/// </summary>
public int? SortCode { get; set; }
/// <summary>
/// Desc:默认模块
/// Default:
/// Nullable:True
/// </summary>
public long? DefaultModule { get; set; }
/// <summary>
/// Desc:状态
/// Default:ENABLE
/// Nullable:True
/// </summary>
public string? Status { get; set; }
/// <summary>
/// Desc:创建时间
/// Default:
/// Nullable:True
/// </summary>
public DateTime? CreateTime { get; set; }
/// <summary>
/// Desc:更新时间
/// Default:
/// Nullable:True
/// </summary>
public DateTime? UpdateTime { get; set; }
/// <summary>
/// Desc:创建者Id
/// Default:
/// Nullable:True
/// </summary>
public long? CreateUserId { get; set; }
/// <summary>
/// Desc:修改者Id
/// Default:
/// Nullable:True
/// </summary>
public long? UpdateUserId { get; set; }
/// <summary>
/// Desc:创建人
/// Default:
/// Nullable:True
/// </summary>
public string? CreateUser { get; set; }
/// <summary>
/// Desc:更新人
/// Default:
/// Nullable:True
/// </summary>
public string? UpdateUser { get; set; }
/// <summary>
/// Desc:软删除
/// Default:true
/// Nullable:True
/// </summary>
public bool? IsDelete { get; set; }
/// <summary>
/// Desc:扩展信息
/// Default:
/// Nullable:True
/// </summary>
public string? ExtJson { get; set; }
/// <summary>
/// Desc:用户id(特意映射)
/// Default:
/// Nullable:False
/// </summary>
[SugarColumn(IsIdentity = true)]
[SugarColumn(ColumnName = "UserId", IsIdentity = true)]
public int UserId { get; set; }
}

View File

@ -54,8 +54,8 @@ public class TrackContentRepository : BasicRepository<TrackContentEntity>, ITrac
{
var pagedList = await Context.Queryable<TrackContentEntity>()
.LeftJoin<TrackStatusEntity>((a, b) => a.TrackStatusId == b.Id && b.IsDeleted == false)
.LeftJoin<VUserEntity>((a, b, e) => a.CreateUserId == e.UserId && e.IsDelete == false)
.LeftJoin<VUserEntity>((a, b, e, f) => a.UpdateUserId == f.UserId && f.IsDelete == false)
.LeftJoin<VUserEntity>((a, b, e) => a.CreateUserId == e.UserId && e.IsDeleted == false)
.LeftJoin<VUserEntity>((a, b, e, f) => a.UpdateUserId == f.UserId && f.IsDeleted == false)
.WhereIF(!input.AppKey.IsNullOrWhiteSpace(), (a, b, e, f) => a.AppKey == input.AppKey)
.WhereIF(!input.Keywords.IsNullOrWhiteSpace(),
(a, b, e, f) => a.Code.Contains(input.Keywords!) || a.Content.Contains(input.Keywords!)

View File

@ -39,8 +39,8 @@ public class TrackFlagRepository : BasicRepository<TrackFlagEntity>, ITrackFlagR
PagedResult<GetTrackFlagListVO> pagedList = new PagedResult<GetTrackFlagListVO>();
pagedList = await Context.Queryable<TrackFlagEntity>()
.LeftJoin<VAppEntity>((a, b) => a.AppKey == b.AppKey && b.IsDeleted == false)
.LeftJoin<VUserEntity>((a, b, c) => a.CreateUserId == c.UserId && c.IsDelete == false)
.LeftJoin<VUserEntity>((a, b, c, d) => a.UpdateUserId == d.UserId && d.IsDelete == false)
.LeftJoin<VUserEntity>((a, b, c) => a.CreateUserId == c.UserId && c.IsDeleted == false)
.LeftJoin<VUserEntity>((a, b, c, d) => a.UpdateUserId == d.UserId && d.IsDeleted == false)
.WhereIF(!input.AppKey.IsNullOrWhiteSpace(), (a, b, c, d) => a.AppKey == input.AppKey)
.WhereIF(!input.Keywords.IsNullOrWhiteSpace(), (a, b, c, d) => SqlFunc.Contains(a.Code, input.Keywords))
.OrderByIF(input.SelectIds.IsNullOrEmpty(), (a, b, c, d) => a.CreateTime, OrderByType.Desc)

View File

@ -37,8 +37,8 @@ public class TrackStatusRepository : BasicRepository<TrackStatusEntity>, ITrackS
public async Task<PagedResult<GetTrackStatusListVO>> GetPageTrackStatus(GetPagedTrackStatusVO input)
{
var pagedList = await Context.Queryable<TrackStatusEntity>()
.LeftJoin<VUserEntity>((a, b) => a.CreateUserId == b.UserId && b.IsDelete == false)
.LeftJoin<VUserEntity>((a, b, d) => a.UpdateUserId == d.UserId && d.IsDelete == false)
.LeftJoin<VUserEntity>((a, b) => a.CreateUserId == b.UserId && b.IsDeleted == false)
.LeftJoin<VUserEntity>((a, b, d) => a.UpdateUserId == d.UserId && d.IsDeleted == false)
.WhereIF(!input.AppKey.IsNullOrWhiteSpace(), (a, b, d) => a.AppKey == input.AppKey)
.WhereIF(!input.Keywords.IsNullOrWhiteSpace(),
(a, b, d) => a.Status.Contains(input.Keywords!) || a.EnStatus.Contains(input.Keywords!) ||