.NET 5项目中如何排除导航属性指定字段 避免JSON输出敏感信息
解决方案
你当前的问题根源是ArticleListDto直接包含了数据库实体Article集合,序列化时会递归输出实体所有属性、导航属性,仅配置ReferenceLoopHandling.Ignore只能解决循环引用报错,无法过滤多余敏感字段。以下是三种实现方案,优先推荐第一种,和你熟悉的Django Rest Framework Serializer逻辑完全对齐:
方案1:自定义DTO(数据传输对象,最规范推荐)
该方案完全解耦API输出结构和数据库实体,和DRF自定义Serializer的作用一致,未在DTO中定义的字段默认不会被序列化,天然实现字段过滤。
- 定义各层级输出DTO,仅保留需要返回的字段:
// 用户输出DTO,排除PasswordHash、Articles等字段 namespace Blog.Entities.Dtos { public class UserOutputDto { public int Id { get; set; } public string UserName { get; set; } // 仅添加你需要对外暴露的用户字段,不要加PasswordHash、Articles等 } }
// 分类输出DTO,排除Articles导航属性 namespace Blog.Entities.Dtos { public class CategoryOutputDto { public int Id { get; set; } public string Name { get; set; } // 仅添加你需要对外暴露的分类字段,不要加Articles等 } }
// 文章输出DTO namespace Blog.Entities.Dtos { public class ArticleOutputDto { public string Title { get; set; } public string Content { get; set; } public string Thumbnail { get; set; } public DateTime Date { get; set; } public int ViewsCount { get; set; } public int CommentCount { get; set; } public string Slug { get; set; } public string SeoAuthor { get; set; } public string SeoDescription { get; set; } public string SeoTags { get; set; } // 用DTO替代原实体类的导航属性 public CategoryOutputDto Category { get; set; } public UserOutputDto User { get; set; } } }
- 修改
ArticleListDto:
namespace Blog.Entities.Dtos { public class ArticleListDto : DtoGetBase { public IList<ArticleOutputDto> Articles { get; set; } } }
- 配置AutoMapper映射规则,你已经在Startup中注册了AutoMapper,新增映射配置类即可:
public class AutoMapperProfile : Profile { public AutoMapperProfile() { CreateMap<Article, ArticleOutputDto>(); CreateMap<User, UserOutputDto>(); CreateMap<Category, CategoryOutputDto>(); } }
- 修改业务层GetAll方法,将查询到的实体转换为DTO后返回:
public async Task<IDataResult<ArticleListDto>> GetAll() { var articles = await _unitOfWork.Articles .GetAllAsync(null, a => a.User, a => a.Category); if (articles.Count > -1) { // 实体转DTO var outputArticles = _mapper.Map<List<ArticleOutputDto>>(articles); return new DataResult<ArticleListDto>(ResultStatus.Success, new ArticleListDto() { Articles = outputArticles, ResultStatus = ResultStatus.Success }); } return new DataResult<ArticleListDto>(ResultStatus.Error, Messages.ArticleMessages.ArticleNotFound, null); }
方案2:[JsonIgnore]属性(临时快速过滤)
如果不想定义太多DTO,可直接在数据库实体类的敏感字段上添加[JsonIgnore]属性,序列化时会自动跳过该字段:
public class User : EntityBase, IEntity { // 其他字段... [JsonIgnore] // 序列化时忽略该字段 public string PasswordHash { get; set; } [JsonIgnore] public ICollection<Article> Articles { get; set; } } public class Category : EntityBase, IEntity { // 其他字段... [JsonIgnore] public ICollection<Article> Articles { get; set; } }
注意:该配置全局生效,若其他接口需要返回这些字段则无法适配,灵活度低于DTO方案。
方案3:动态序列化过滤(按需自定义)
如果需要不同接口返回不同字段,可自定义Newtonsoft.Json序列化过滤器,实现类似DRFexclude参数的动态过滤效果,一般场景下前两种方案即可覆盖需求。
内容的提问来源于stack exchange,提问作者ATK
相关产品推荐
相关产品推荐

