using Dpz.Core.Public.Entity.Auth;
using Dpz.Core.Service.Mediator.Features.Auth.Contracts;
namespace Dpz.Core.Service.Mediator.Features.Auth.Queries;
public class SearchAuthTokensQueryHandler(
IRepository<DpzToken> tokenRepository,
IRepository<DpzApplication> applicationRepository
) : IRequestHandler<SearchAuthTokensQuery, PagedListWarp<AuthTokenPageItem>>
{
public async ValueTask<PagedListWarp<AuthTokenPageItem>> Handle(
SearchAuthTokensQuery request,
CancellationToken cancellationToken
)
{
var query = tokenRepository.SearchFor(x => true);
if (!string.IsNullOrWhiteSpace(request.UserId))
{
query = query.Where(x => x.Subject == request.UserId);
}
if (
!string.IsNullOrWhiteSpace(request.ClientId)
&& ObjectId.TryParse(request.ClientId, out var appId)
)
{
query = query.Where(x => x.ApplicationId == appId);
}
var pagedList = await query
.OrderByDescending(x => x.Id)
.ToPagedListAsync(request.Page, request.Limit, cancellationToken);
var applicationIds = pagedList.Select(x => x.ApplicationId).ToHashSet();
var applications = await applicationRepository
.SearchFor(Builders<DpzApplication>.Filter.In(x => x.Id, applicationIds))
.ToListAsync(cancellationToken);
var items = pagedList
.Select(x =>
{
var app = applications.FirstOrDefault(y => y.Id == x.ApplicationId);
return new AuthTokenPageItem
{
Id = x.Id.ToString(),
ApplicationId = x.ApplicationId.ToString(),
ApplicationName = app?.DisplayName,
AuthorizationId = x.AuthorizationId.ToString(),
ConcurrencyToken = x.ConcurrencyToken,
CreationDate = x.CreationDate,
ExpirationDate = x.ExpirationDate,
Payload = x.Payload,
Properties = x.Properties,
RedemptionDate = x.RedemptionDate,
ReferenceId = x.ReferenceId,
Status = x.Status,
Subject = x.Subject,
Type = x.Type,
};
})
.ToList();
return new PagedListWarp<AuthTokenPageItem>(
pagedList.CurrentPageIndex,
pagedList.PageSize,
pagedList.TotalItemCount,
items
);
}
}
⚠⚠ 以下内容为AI分析的结果,请根据实际情况进行判断。
代码解释
这是一个基于 MediatR 模式的查询处理器(Query Handler),用于分页搜索认证令牌(Auth Tokens)。
核心功能
该处理器实现了 SearchAuthTokensQuery 查询请求的处理逻辑,返回分页的令牌列表。
代码结构分析
1. 类定义与依赖注入
public class SearchAuthTokensQueryHandler(
IRepository<DpzToken> tokenRepository,
IRepository<DpzApplication> applicationRepository
) : IRequestHandler<SearchAuthTokensQuery, PagedListWarp<AuthTokenPageItem>>
- 使用 C# 12 主构造函数语法注入两个仓储:
tokenRepository: 令牌数据仓储applicationRepository: 应用程序数据仓储
- 实现
IRequestHandler接口,处理查询并返回分页结果
2. 查询逻辑流程
步骤 1: 构建基础查询
var query = tokenRepository.SearchFor(x => true);
初始化查询(获取所有令牌)
步骤 2: 条件过滤
// 按用户ID过滤
if (!string.IsNullOrWhiteSpace(request.UserId))
query = query.Where(x => x.Subject == request.UserId);
// 按应用客户端ID过滤
if (!string.IsNullOrWhiteSpace(request.ClientId) && ObjectId.TryParse(request.ClientId, out var appId))
query = query.Where(x => x.ApplicationId == appId);
根据请求参数动态添加过滤条件
步骤 3: 分页查询
var pagedList = await query
.OrderByDescending(x => x.Id) // 按ID降序排序
.ToPagedListAsync(request.Page, request.Limit, cancellationToken);
步骤 4: 关联查询应用信息
var applicationIds = pagedList.Select(x => x.ApplicationId).ToHashSet();
var applications = await applicationRepository
.SearchFor(Builders<DpzApplication>.Filter.In(x => x.Id, applicationIds))
.ToListAsync(cancellationToken);
- 提取所有令牌关联的应用ID
- 批量查询应用信息(避免 N+1 查询问题)
步骤 5: 数据映射
var items = pagedList.Select(x => {
var app = applications.FirstOrDefault(y => y.Id == x.ApplicationId);
return new AuthTokenPageItem {
ApplicationName = app?.DisplayName, // 关联应用名称
// ... 其他字段映射
};
}).ToList();
将数据库实体转换为 DTO(AuthTokenPageItem),并补充应用名称
步骤 6: 返回分页结果
return new PagedListWarp<AuthTokenPageItem>(
pagedList.CurrentPageIndex,
pagedList.PageSize,
pagedList.TotalItemCount,
items
);
设计亮点
- ✅ 仓储模式:数据访问逻辑解耦
- ✅ MediatR 中介者模式:请求/处理分离
- ✅ 性能优化:批量加载关联数据,避免 N+1 查询
- ✅ 动态查询:根据参数灵活过滤
- ✅ 异步操作:使用
async/await提高并发性能 - ✅ 取消令牌支持:允许取消长时间运行的查询
应用场景
适用于OAuth 2.0 / OpenID Connect 令牌管理系统,提供:
- 管理员查看所有令牌
- 按用户/应用过滤令牌
- 令牌审计和监控功能
AI 正在分析代码…
评论加载中...