SpringBoot中结合SimplePropertyPreFilter排除JSON敏感属性

在SpringBoot开发中,经常需要从JSON响应中排除敏感属性(如密码、身份证号等),FastJson提供的SimplePropertyPreFilter及其扩展类是实现这一需求的常用方案。以下是详细的实现方法和最佳实践:

1. 基础实现方案

1.1 直接使用SimplePropertyPreFilter

最简单的实现方式是直接在Controller中创建SimplePropertyPreFilter实例并指定要排除的字段:

sql 复制代码
@GetMapping("/user")
public String getUser() {
    User user = new User("张三", "123456", "1828381828225677");
    
    SimplePropertyPreFilter filter = new SimplePropertyPreFilter();
    filter.getExcludes().add("password");
    filter.getExcludes().add("idNo");
    
    return JSON.toJSONString(user, filter);
}

这种方式简单直接,但需要在每个接口重复编写过滤逻辑。

1.2 使用PropertyPreExcludeFilter扩展类

可以创建一个继承自SimplePropertyPreFilter的扩展类,提供更便捷的链式调用:

typescript 复制代码
public class PropertyPreExcludeFilter extends SimplePropertyPreFilter {
    public PropertyPreExcludeFilter addExcludes(String... filters) {
        for (String filter : filters) {
            this.getExcludes().add(filter);
        }
        return this;
    }
}

// 使用示例
@GetMapping("/user")
public String getUser() {
    User user = new User("张三", "123456", "1828381828225677");
    
    PropertyPreExcludeFilter filter = new PropertyPreExcludeFilter()
        .addExcludes("password", "idNo");
    
    return JSON.toJSONString(user, filter);
}

这种方式通过链式调用简化了代码,提高了可读性。

2. 全局配置方案

2.1 配置FastJsonHttpMessageConverter

在SpringBoot中,可以通过配置FastJsonHttpMessageConverter实现全局过滤:

java 复制代码
@Configuration
public class FastJsonConfig {
    
    @Bean
    public FastJsonHttpMessageConverter fastJsonHttpMessageConverter() {
        FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
        FastJsonConfig config = new FastJsonConfig();
        
        // 配置全局过滤器
        PropertyPreExcludeFilter filter = new PropertyPreExcludeFilter()
            .addExcludes("password", "idNo", "creditCard");
        
        config.setSerializeFilters(filter);
        converter.setFastJsonConfig(config);
        return converter;
    }
}

这种配置会对所有使用FastJson序列化的响应生效。

2.2 结合AOP实现动态过滤

对于需要根据不同接口动态过滤不同字段的场景,可以使用AOP:

java 复制代码
@Aspect
@Component
public class SensitiveDataAspect {
    
    @Around("@annotation(com.example.SensitiveData)")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        Object result = joinPoint.proceed();
        
        SensitiveData sensitiveData = ((MethodSignature) joinPoint.getSignature())
            .getMethod().getAnnotation(SensitiveData.class);
        
        PropertyPreExcludeFilter filter = new PropertyPreExcludeFilter()
            .addExcludes(sensitiveData.excludes());
        
        return JSON.toJSONString(result, filter);
    }
}

// 自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface SensitiveData {
    String[] excludes();
}

// 使用示例
@GetMapping("/user")
@SensitiveData(excludes = {"password", "idNo"})
public User getUser() {
    return new User("张三", "123456", "1828381828225677");
}

这种方式提供了最大的灵活性,可以根据不同接口需求定制过滤规则。

3. 高级应用场景

3.1 结合注解实现条件过滤

可以自定义注解实现更智能的过滤,如根据字段值决定是否序列化:

java 复制代码
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomizeJsonExclude {
}

// 自定义过滤器
public class CustomPropertyPreFilter implements PropertyPreFilter {
    @Override
    public boolean apply(JSONSerializer serializer, Object source, String name) {
        try {
            Field field = source.getClass().getDeclaredField(name);
            field.setAccessible(true);
            
            // 检查是否有自定义注解
            if (field.isAnnotationPresent(CustomizeJsonExclude.class)) {
                Object value = field.get(source);
                return value != null; // 值为null时不序列化
            }
            return true;
        } catch (Exception e) {
            return true;
        }
    }
}

// 配置到FastJsonConfig中
@Bean
public FastJsonHttpMessageConverter fastJsonHttpMessageConverter() {
    FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
    FastJsonConfig config = new FastJsonConfig();
    config.setSerializeFilters(new CustomPropertyPreFilter());
    converter.setFastJsonConfig(config);
    return converter;
}

这种方式类似于Jackson的@JsonInclude注解功能。

3.2 多过滤器组合使用

FastJson支持同时使用多个过滤器:

typescript 复制代码
// 排除敏感字段的过滤器
PropertyPreExcludeFilter sensitiveFilter = new PropertyPreExcludeFilter()
    .addExcludes("password", "idNo");

// 格式化BigDecimal的过滤器
ValueFilter decimalFilter = (object, name, value) -> {
    if (value instanceof BigDecimal) {
        return ((BigDecimal) value).setScale(2, RoundingMode.HALF_UP);
    }
    return value;
};

// 在Controller中使用
@GetMapping("/account")
public String getAccount() {
    Account account = accountService.getCurrentAccount();
    
    return JSON.toJSONString(account, sensitiveFilter, decimalFilter);
}

这种组合方式可以同时处理字段排除和值格式化等需求。

4. 最佳实践建议

  1. 性能考虑:频繁创建过滤器实例会影响性能,建议将常用过滤器配置为单例
  2. 安全基线 :定义项目统一的敏感字段清单,如password, idNo, phone, email等
  3. 日志处理:在日志打印时也应使用相同的过滤逻辑,避免敏感信息泄露
  4. 文档维护:在API文档中明确标注哪些字段会被自动过滤
  5. 测试验证:编写测试用例验证过滤逻辑,特别是边界条件如null值、空字符串等

5. 与其他方案的对比

方案 优点 缺点 适用场景
SimplePropertyPreFilter 简单直接,无需配置 代码重复,不够灵活 简单项目或临时方案
全局配置 一次配置,全局生效 不够灵活,所有接口使用相同规则 敏感字段固定的项目
AOP+注解 高度灵活,可定制 实现复杂,需要额外配置 复杂项目,不同接口需要不同规则
Jackson注解 声明式,与SpringBoot集成好 需要切换JSON库 新项目或可接受Jackson的项目

在FastJson生态中,SimplePropertyPreFilter及其扩展类提供了简单有效的敏感字段过滤方案,特别适合已经在使用FastJson的项目。

相关推荐
兔子零10243 分钟前
架构师最危险的能力:用正确的技术,做出错误的架构决策
前端·javascript·后端
ytadpole3 分钟前
模板下载性能优化记录
后端·性能优化
执团搓锐6 分钟前
个人知识库助手
后端
楼南7 分钟前
数字化体验:从下单到收获的全过程
后端
武子康8 分钟前
Coding Agent 的知识也会漂移:用固定快照检查 Vercel Plugin 升级
人工智能·后端·agent
货拉拉技术24 分钟前
JDK 21 规模化落地实践
后端
isfox27 分钟前
MapTask 工作机制:从读数据到写磁盘,一个 Map 任务的完整一生
后端
aibo86030828 分钟前
基于 Spring Boot 的茶铺管理系统设计与实现
java·spring boot·后端
掘金酱1 小时前
带着作品来,坐下来聊|掘金 X-lab · Coffee Talk 邀请你来见一面
前端·javascript·后端
唐青枫2 小时前
企业知识库 RAG 实战:混合检索、权限过滤与答案溯源
后端