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的项目。

相关推荐
天天摸鱼的java工程师3 小时前
Java IO 流 + MinIO:游戏玩家自定义头像上传(格式校验、压缩处理、存储管理)
java·后端
Cache技术分享3 小时前
207. Java 异常 - 访问堆栈跟踪信息
前端·后端
功能啥都不会3 小时前
MySql基本语法对照表
后端
程序员小富3 小时前
改了 Nacos 一行配置,搞崩线上支付系统!
java·后端
golang学习记3 小时前
MCP官方 Go SDK v1.0 正式发布,我立马实现了自己的MCP server
后端
知其然亦知其所以然3 小时前
面试官一开口就问:“你了解MySQL水平分区吗?”我当场差点懵了……
后端·mysql·面试
GeekAGI3 小时前
使用 curl 进行并发请求的指南:7种方法详解
后端
BingoGo3 小时前
PHP 开发者应该理解的 Linux 入门权限指南
后端·php
堇未央3 小时前
求助,无法获取到最新的数据
后端