跳到主要内容

IGeekFan.FreeKit.Infrastructure

核心基础设施项目,提供 Controller 基类、DDD 约定、认证授权、缓存、异常通知等能力。

功能概览

功能说明
Controller 基类FreeKitController 统一基类
认证授权JWT / OpenIddict 认证、权限验证
缓存Redis / 内存缓存
异常体系BusinessException + 通知
过滤器异常通知、数据脱敏
工具类AES/DES/SM4/MD5 加解密

Controller 基类

KitApiControllerBase

最底层基类,不需要认证:

[ApiController]
public abstract class KitApiControllerBase : ControllerBase
{
}

FreeKitController

带认证的基类,大多数控制器继承这个:

[Authorize]
public abstract class FreeKitController : KitApiControllerBase
{
}

使用示例

// 需要认证的 API
[ApiController]
[Route("api/[controller]")]
public class ArticleController : FreeKitController
{
private readonly IArticleService _articleService;

public ArticleController(IArticleService articleService)
{
_articleService = articleService;
}

[HttpGet]
public async Task<IActionResult> GetList()
{
var articles = await _articleService.GetListAsync();
return Ok(articles);
}
}

// 不需要认证的 API
[ApiController]
[Route("api/[controller]")]
public class PublicController : KitApiControllerBase
{
[HttpGet("health")]
public IActionResult Health() => Ok("ok");
}

应用服务基类

ApplicationService

提供常用服务的懒加载注入:

public class ArticleService : ApplicationService, IArticleService
{
private readonly IArticleRepository _repository;

public ArticleService(IArticleRepository repository)
{
_repository = repository;
}

public async Task<List<ArticleDto>> GetListAsync()
{
// CurrentUser - 当前用户
// UnitOfWorkManager - 工作单元
// Mediator - MediatR 中介者
// CapPublisher - 分布式事件发布
// Logger - 日志
// AuthorizationService - 授权服务
// PermissionStore - 权限存储

var userId = CurrentUser.FindUserId();
var articles = await _repository.GetListAsync();
return articles.MapTo<List<ArticleDto>>();
}
}

ApplicationService 可用服务

属性类型说明
CurrentUserICurrentUser当前用户信息
UnitOfWorkManagerUnitOfWorkManager工作单元管理器
MediatorIMediatorMediatR 中介者
CapPublisherICapPublisherCAP 分布式事件发布
LoggerILogger日志记录器
AuthorizationServiceIAuthorizationService授权服务
PermissionStoreIPermissionStore权限存储

CrudAppService

CRUD 应用服务模板:

public class ArticleCrudService : CrudAppService<
Article, // 实体
ArticleDto, // 输出 DTO
ArticleListDto, // 列表 DTO
Guid, // 主键类型
PageQuery, // 查询参数
CreateArticleRequest, // 创建请求
UpdateArticleRequest // 更新请求
>, IArticleCrudService
{
public ArticleCrudService(IBaseRepository<Article, Guid> repository) : base(repository)
{
}
}

// 自动获得:GetListAsync / GetAsync / CreateAsync / UpdateAsync / DeleteAsync

CrudAppService 可重写方法

方法说明
CreateFilteredQuery()自定义查询过滤器
ApplySorting()自定义排序逻辑
EntityListToDtoListAsync()自定义实体到 DTO 映射
GetEntityByIdAsync()获取实体并验证权限
ValidateEntityPermissions()验证实体权限

领域服务基类

DomainService

public class OrderDomainService : DomainService, IOrderDomainService
{
private readonly IOrderRepository _repository;

public OrderDomainService(IOrderRepository repository)
{
_repository = repository;
}

public async Task ProcessOrderAsync(Guid orderId)
{
// CurrentUser - 当前用户
// UnitOfWorkManager - 工作单元
// Logger - 日志

var order = await _repository.FindAsync(orderId);
// 业务逻辑...
}
}

DomainService 可用服务

属性类型说明
CurrentUserICurrentUser当前用户信息
UnitOfWorkManagerUnitOfWorkManager工作单元管理器
LoggerILogger日志记录器
AuthorizationServiceIAuthorizationService授权服务
CurrentUnitOfWorkIUnitOfWork当前工作单元

领域事件分发

public class OrderDomainService : DomainService, IOrderDomainService
{
private readonly IDomainEventDispatcher _eventDispatcher;

public async Task PlaceOrderAsync(Order order)
{
// 业务逻辑...

// 添加领域事件
order.AddDomainEvent(new OrderPlacedEvent(order.Id));

// 分发事件
await _eventDispatcher.DispatchAndClearEvents(new[] { order });
}
}

缓存系统

两种缓存策略

策略说明
CacheStrategyType.Redis基于 FreeRedis
CacheStrategyType.Memory基于 ConcurrentDictionary

使用方式

// 1. 注册缓存服务
builder.Services.AddCacheStrategy(CacheStrategyType.Redis);

// 2. 在服务中使用
public class ArticleService : IScopedDependency
{
private readonly ICacheService _cache;

public ArticleService(ICacheService cache) => _cache = cache;

public async Task<Article> GetByIdAsync(Guid id)
{
// 带缓存壳的读取
return await _cache.CacheShell(
$"article:{id}",
async () => await _repository.FindAsync(id),
expireSeconds: 300
);
}
}

// 3. 或使用 AOP 缓存
[Cacheable(CacheKey = "article:{id}", ExpireSeconds = 300)]
public async Task<Article> GetByIdAsync(Guid id)
{
return await _repository.FindAsync(id);
}

Cacheable 特性

[Cacheable(
CacheKey = "user:{userId}", // 缓存键,支持 {参数名}
ExpireSeconds = 300, // 过期时间(秒)
CacheStrategy = CacheStrategyType.Redis // 缓存策略
)]
public async Task<UserDto> GetUserAsync(Guid userId) { ... }

异常体系

常用异常

// 业务异常
throw new BusinessException("订单状态不允许操作");

// 实体不存在
throw new EntityNotFoundException(typeof(Article), id);

// 请求异常
throw new BadRequestException("参数无效");

// 带 Guard 验证
Guard.NegativeOrZero(amount, nameof(amount));
Guard.Null(order, nameof(order));
Guard.NotFound(id, nameof(id));

异常类型

异常类说明
BusinessException业务异常,带 Code 和 StatusCode
EntityNotFoundException实体不存在
BadRequestException请求参数错误
InvalidEmailException无效邮箱格式
InvalidDateException无效日期

统一响应

// 成功
return Ok(ApiResponse.Ok(data));

// 失败
return BadRequest(ApiResponse.Failed("错误信息"));

// 业务异常
throw new BusinessException(ResponseCode.BusinessException, "业务错误");

ResponseCode 枚举

说明
Success(0)成功
BusinessException(1001)业务异常
Failed(1002)失败
AuthenticationFailed(10000)认证失败
NoPermission(10001)无权限
NotFound(10020)未找到
ParameterError(10030)参数错误
TokenExpired(10050)Token 过期
ManyRequests(10140)请求过多

授权系统

权限验证

// 方式一:使用 Policy
[Authorize(Policy = "Article.Create")]
public IActionResult Create() { }

// 方式二:使用特性
[KitAuthorize("Article.Delete")]
public IActionResult Delete() { }

认证模式

public enum AuthMode
{
Jwt = 0, // JWT 自签发
OpenIddict = 1 // OpenIddict 验证
}

JWT 配置

{
"JwtSettings": {
"Issuer": "https://localhost:5001",
"Audience": "https://localhost:5001",
"SecretKey": "your-secret-key-min-32-chars",
"ExpireMinutes": 60
}
}

CookieJwtBearerHandler

支持三种 Token 来源:

  1. Query string (?access_token=...) - SignalR Hub
  2. Authorization header - 标准 JWT
  3. Cookie (access_token cookie)

实现权限存储

public class PermissionStore : IPermissionStore
{
public async Task<bool> CheckPermissionAsync(string permission)
{
// 检查用户是否有指定权限
}

public async Task<bool> CheckAccessTokenAsync(string accessToken)
{
// 检查 Token 是否有效
}
}

异常通知

支持三通道告警:邮件、飞书、企业微信。

{
"ExceptionNotify": {
"Enabled": true,
"Mail": {
"Enabled": true,
"MailTo": "ops@example.com"
},
"Feishu": {
"Enabled": true,
"WebhookUrl": "https://open.feishu.cn/..."
},
"WeCom": {
"Enabled": false
}
}
}

加密工具

AES 加密

var encrypted = AESUtil.Encrypt(plainText, key, iv);
var decrypted = AESUtil.Decrypt(encrypted, key, iv);

DES 加密

var encrypted = DESUtil.Encrypt(plainText, key, iv);
var decrypted = DESUtil.Decrypt(encrypted, key, iv);

SM4 国密

var key = SM4Util.GenerateKey();
var encrypted = SM4Util.Encrypt_CBC_Padding(key, iv, data);
var decrypted = SM4Util.Decrypt_CBC_Padding(key, iv, encrypted);

MD5 哈希

var hash32 = Md5Util.Md5(plainText, MD5Digit.Digit32);
var hash16 = Md5Util.Md5(plainText, MD5Digit.Digit16);
var verified = EncryptUtil.Verify(md5Hash, plainText);

Base64 编码

var encoded = ToolHelper.Base64Encode(content);
var decoded = ToolHelper.Base64Decode(encoded);

数据脱敏

var masked = MaskHelper.MaskPhoneNumber("13812345678");
// 结果: "138****5678"

中间件

加密中间件

// Program.cs
app.UseEncryption();

// 配置
{
"Encryption": {
"Enable": true,
"EncryptionKey": "your-key",
"EncryptionIV": "your-iv"
}
}

Basic 认证中间件

// 保护 Swagger
{
"Basic": {
"Enable": true,
"ProtectPaths": ["/swagger"],
"UserName": "admin",
"UserPassword": "123456"
}
}

IP 限流

// 注册限流服务
builder.Services.AddIpRateLimiting(builder.Configuration);

// 配置
{
"IpRateLimiting": {
"Enable": true,
"MaxRequestsPerSecond": 10,
"RetryAfterSeconds": 60
}
}

过滤器

SensitiveDataAttribute

数据脱敏过滤器:

public class UserDto
{
[SensitiveData]
public string Phone { get; set; } // 自动脱敏

[SensitiveData(Mask = "***")]
public string Email { get; set; }
}

RecaptchaVerifyActionFilter

Google reCAPTCHA 验证:

[ServiceFilter(typeof(RecaptchaVerifyActionFilter))]
[HttpPost]
public IActionResult Submit(SubmitRequest request)
{
// 自动验证 reCAPTCHA
}

安全工具

CurrentUserExtensions

// 获取用户 ID
var userId = CurrentUser.FindUserId();

// 检查是否管理员
if (CurrentUser.IsAdmin()) { ... }

// 检查是否模拟登录
if (CurrentUser.IsImpersonating()) { ... }

// 获取模拟者信息
var impersonatorId = CurrentUser.FindImpersonatorUserId();

DTO 基类

ApiResponse

// 成功响应
return Ok(ApiResponse.Ok(data));

// 失败响应
return BadRequest(ApiResponse.Failed("错误信息"));

// 带状态码
return Ok(ApiResponse.New(ResponseCode.Success, data));

PageQuery

分页查询基类:

public class ArticleListQuery : PageQuery
{
public string? Keyword { get; set; }
}

// 使用
[HttpGet]
public async Task<PagerListDto<ArticleDto>> GetList(ArticleListQuery query)
{
return await _articleService.GetListAsync(query);
}

ISortedResultRequest

排序支持:

// 通过逗号分隔排序
// 例如: "Name ASC, Age DESC"
public string? Sorting { get; set; }

扩展方法

分页扩展

// FreeSql 分页
var list = await _fsql.Select<Article>()
.ToPagerListAsync(query);

// 内存分页
var list = articles.ToPagerList(query);

文件扩展

// 递归获取文件
var files = fileProvider.GetFilesRecursively();

// 读取文件内容
var content = await fileInfo.ReadAsStringAsync();

CAP 扩展

// 开启事务
ICapTransaction tx = unitOfWork.BeginTransaction(publisher, autoCommit: false);

// 提交事务
tx.Commit(unitOfWork);

相关文档