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

相关推荐
SmartBrain21 分钟前
Spring Boot的高性能技术栈的工程实践
spring boot·后端·架构
AMoon丶39 分钟前
Golang--内存管理
开发语言·后端·算法·缓存·golang·os
zabr1 小时前
花了 100+ 篇笔记,我整理出 了一套 AI Agent 工程完全指南
前端·后端·agent
神奇小汤圆1 小时前
Java面试题及答案整理(2026年金三银四最新版,持续更新)
后端
uzong1 小时前
“腾讯QClaw全面开放”,不花 Token 钱、真正体验一把小龙虾的快乐,最低成本全面了解龙虾
人工智能·后端
楼田莉子1 小时前
C++高并发内存池:内存池调优与测试
c++·后端·哈希算法·visual studio
短剑重铸之日1 小时前
《ShardingSphere解读》16 改写引擎:如何理解装饰器模式下的 SQL 改写实现机制?
java·数据库·后端·sql·shardingsphere·分库分表·装饰器模式
q5431470871 小时前
VScode 开发 Springboot 程序
java·spring boot·后端
学习要积极2 小时前
Springboot图片验证码-EasyCaptcha
java·spring boot·后端
Nyarlathotep01132 小时前
可重入锁ReentrantLock基础和原理
后端