ASP.NET Core 2.0 Web API:AutoMapper配置文件中获取登录用户
在ASP.NET Core 2.0中给AutoMapper配置添加当前授权用户信息
我之前在ASP.NET Core 2.0的Web API项目里刚好处理过类似的需求,要在ViewModel转DTO的AutoMapper映射中自动填充BaseEntity的审计字段(CreatedBy、ModifiedBy这些),给你两个靠谱的实现方案:
方案一:使用AutoMapper的IMappingAction(推荐)
这个方案的优势是统一处理所有需要填充审计字段的映射,不用在每个Controller里重复传参,符合DRY原则。
步骤1:注册IHttpContextAccessor
ASP.NET Core 2.0默认没有把IHttpContextAccessor注册到DI容器,所以先在Startup.cs的ConfigureServices方法里添加:
services.AddHttpContextAccessor();
步骤2:创建自定义审计字段填充Action
这个Action会注入IHttpContextAccessor来获取当前授权用户的ID,然后自动填充DTO的审计字段:
// 先定义你的BaseEntity对应的DTO基类,确保包含审计字段 public class BaseEntityDto { public Guid Id { get; set; } public DateTime CreatedOn { get; set; } public Guid CreatedBy { get; set; } public DateTime ModifiedOn { get; set; } public Guid ModifiedBy { get; set; } } // 自定义MappingAction public class SetAuditFieldsAction<TDto> : IMappingAction<object, TDto> where TDto : BaseEntityDto { private readonly IHttpContextAccessor _httpContextAccessor; public SetAuditFieldsAction(IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor; } public void Process(object source, TDto destination, ResolutionContext context) { // 从HttpContext中获取当前用户ID(这里假设你的用户ID存在NameIdentifier声明里) var userIdClaim = _httpContextAccessor.HttpContext.User.FindFirst(ClaimTypes.NameIdentifier); if (userIdClaim == null) { // 可以根据业务需求抛出异常或者做默认处理 throw new UnauthorizedAccessException("未找到当前授权用户ID"); } var currentUserId = Guid.Parse(userIdClaim.Value); // 填充审计字段,这里可以根据业务区分新建/更新场景,比如判断source是否是新建的ViewModel destination.CreatedBy = currentUserId; destination.CreatedOn = DateTime.UtcNow; destination.ModifiedBy = currentUserId; destination.ModifiedOn = DateTime.UtcNow; } }
步骤3:在AutoMapper配置中应用这个Action
在你的ViewModel转DTO的配置文件里,给需要填充审计字段的映射添加AfterMap调用:
public class ViewModelToDtoProfile : Profile { public ViewModelToDtoProfile() { // 单个映射示例 CreateMap<ProductViewModel, ProductDto>() .AfterMap<SetAuditFieldsAction<ProductDto>>(); // 其他需要审计字段的映射都可以复用这个Action CreateMap<OrderViewModel, OrderDto>() .AfterMap<SetAuditFieldsAction<OrderDto>>(); } }
方案二:映射时通过上下文传递用户ID
如果你的业务场景需要更灵活的控制(比如某些映射不需要填充审计字段),可以在Controller调用Map的时候手动传递用户ID:
步骤1:在Controller中传递用户ID
[Authorize] [ApiController] [Route("api/products")] public class ProductsController : ControllerBase { private readonly IMapper _mapper; public ProductsController(IMapper mapper) { _mapper = mapper; } [HttpPost] public IActionResult Create(ProductViewModel viewModel) { var currentUserId = Guid.Parse(User.FindFirst(ClaimTypes.NameIdentifier).Value); // 通过AutoMapper的上下文传递用户ID var productDto = _mapper.Map<ProductDto>(viewModel, opt => opt.Items["CurrentUserId"] = currentUserId); // 后续保存逻辑... return Ok(productDto); } }
步骤2:在AutoMapper配置中读取上下文参数
public class ViewModelToDtoProfile : Profile { public ViewModelToDtoProfile() { CreateMap<ProductViewModel, ProductDto>() .ForMember(dest => dest.CreatedBy, opt => opt.MapFrom((src, dest, _, context) => context.Items["CurrentUserId"])) .ForMember(dest => dest.ModifiedBy, opt => opt.MapFrom((src, dest, _, context) => context.Items["CurrentUserId"])) .ForMember(dest => dest.CreatedOn, opt => opt.MapFrom(_ => DateTime.UtcNow)) .ForMember(dest => dest.ModifiedOn, opt => opt.MapFrom(_ => DateTime.UtcNow)); } }
注意事项
- 确保你的认证配置已经正确设置,
User对象能获取到有效的用户ID声明; - 方案一中的
SetAuditFieldsAction可以根据业务需求调整,比如区分新建和更新操作(比如通过ViewModel的Id是否为空来判断); - 建议使用
DateTime.UtcNow而不是本地时间,避免时区问题。
内容的提问来源于stack exchange,提问作者unixxx
相关产品推荐
相关产品推荐

