Spring Security 7.0 迁移指南

Spring Security 7.0 迁移指南

重要说明: Spring Security 7.0 包含重大更改。在升级到 7.0 之前,请使用 Spring Security 6.5 作为准备版本。Spring Security 6.5 允许你逐步迁移单个功能,使升级风险降至最低。

有关新功能的详细信息,请参阅 What's New

目录

概述

本指南涵盖了从 Spring Security 6.x 迁移到 7.0 的步骤。Spring Security 7.0 代表了框架的重大现代化,移除了长期弃用的 API 并提高了一致性。

主要迁移主题:

  • 授权API: 从 AccessDecisionManager 完全迁移到 AuthorizationManager
  • 配置 : 移除 and() 方法,XML schema 版本要求
  • 请求匹配: 基于 PathPatternRequestMatcher 的标准化
  • Jackson: 迁移到 Jackson 3
  • OAuth 2.0: 默认启用 PKCE,移除密码授权
  • SAML 2.0: 改进的规范合规性,要求 OpenSAML 5
  • 模块架构: 集成以前独立的项目

版本要求

在迁移到 Spring Security 7.0 之前,请确保你的项目满足以下版本要求:

  • Spring Framework: 6.x
  • Spring Boot: 4.0.x
  • Java: 17+
  • Jakarta EE: 9+

版本兼容性矩阵

Spring Security Spring Boot Java
7.0.x 4.0.x 17+
6.5.x 3.2.x 17+
6.4.x 3.1.x 17+

依赖更新

Maven 配置

pom.xml 中更新以下依赖:

xml 复制代码
<!-- Spring Boot 4.0 -->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>4.0.0</version>
    <relativePath/>
</parent>

<!-- Spring Security 7.0 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

<!-- 如果使用 OAuth 2.0 授权服务器 -->
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-oauth2-authorization-server</artifactId>
</dependency>

<!-- 如果使用 SAML 2.0 -->
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-saml2-service-provider</artifactId>
</dependency>

<!-- 如果使用 LDAP -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-ldap</artifactId>
</dependency>

Gradle 配置

build.gradle 中更新依赖:

gradle 复制代码
// Spring Boot 4.0
plugins {
    id 'org.springframework.boot' version '4.0.0'
    id 'io.spring.dependency-management' version '1.1.4'
}

// Spring Security 7.0
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-security'
    
    // 可选依赖
    implementation 'org.springframework.security:spring-security-oauth2-authorization-server'
    implementation 'org.springframework.security:spring-security-saml2-service-provider'
    implementation 'org.springframework.boot:spring-boot-starter-ldap'
}

核心API变更

AuthorizationManager#check 移除

AuthorizationManager 接口中的 check 方法已被移除。使用 authorize 方法替代。

迁移前 (6.x):

java 复制代码
AuthorizationManager<RequestAuthorizationContext> authorizationManager = (authentication, object) -> {
    // ... 授权逻辑
    authorizationDecision = check(authentication, object);
};

迁移后 (7.0):

java 复制代码
AuthorizationManager<RequestAuthorizationContext> authorizationManager = (authentication, object) -> {
    // ... 授权逻辑
    authorizationDecision = AuthorizationDecision.from(hasRole("ADMIN"));
};

Access Decision API

如果你使用 Access Decision API,需要添加 spring-security-access 模块。

Maven:

xml 复制代码
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-access</artifactId>
</dependency>

Gradle:

gradle 复制代码
implementation 'org.springframework.security:spring-security-access'

新增 Authentication.Builder API

Spring Security 7.0 引入了新的 Authentication.Builder API 用于构建身份验证对象:

java 复制代码
// 构建用户名密码认证
Authentication authentication = UsernamePasswordAuthenticationToken.builder()
    .principal("user")
    .credentials("password")
    .authorities("ROLE_USER")
    .build();

// 构建 OAuth2 认证
OAuth2AuthenticationToken oauth2Token = OAuth2AuthenticationToken.builder()
    .principal(oauth2User)
    .clientRegistrationId("google")
    .authorizedScopes(Arrays.asList("openid", "profile"))
    .build();

XML配置更新

命名空间Schema要求

Spring Security 7.0 要求 XML 配置使用 7.0 schema。更新你的 XML 配置:

迁移前 (6.x):

xml 复制代码
<beans xmlns:security="http://www.springframework.org/schema/security"
       xsi:schemaLocation="
           http://www.springframework.org/schema/security
           https://www.springframework.org/schema/security/spring-security-6.0.xsd">

迁移后 (7.0) - 选项1:显式版本

xml 复制代码
<beans xmlns:security="http://www.springframework.org/schema/security"
       xsi:schemaLocation="
           http://www.springframework.org/schema/security
           https://www.springframework.org/schema/security/spring-security-7.0.xsd">

迁移后 (7.0) - 选项2:无版本(推荐)

xml 复制代码
<beans xmlns:security="http://www.springframework.org/schema/security"
       xsi:schemaLocation="
           http://www.springframework.org/schema/security
           https://www.springframework.org/schema/security/spring-security.xsd">

SecurityNamespaceHandler 在解析时强制执行此要求。

Java配置变更

移除 and() 方法

HttpSecurity DSL 中的 and() 方法已被移除。使用基于lambda的配置替代。

迁移前 (6.x):

java 复制代码
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        .authorizeHttpRequests(authz -> authz
            .requestMatchers("/public/**").permitAll()
            .anyRequest().authenticated()
        )
        .and()
        .formLogin(form -> form
            .loginPage("/login")
            .permitAll()
        )
        .and()
        .logout(logout -> logout.permitAll());
    return http.build();
}

迁移后 (7.0):

java 复制代码
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        .authorizeHttpRequests(authz -> authz
            .requestMatchers("/public/**").permitAll()
            .anyRequest().authenticated()
        )
        .formLogin(form -> form
            .loginPage("/login")
            .permitAll()
        )
        .logout(logout -> logout.permitAll());
    return http.build();
}

授权配置

移除 authorizeRequests()

authorizeRequests() 方法已被移除。使用 authorizeHttpRequests() 替代。

迁移:

java 复制代码
// 迁移前 (6.x)
http.authorizeRequests(authz -> authz
    .requestMatchers("/admin/**").hasRole("ADMIN")
    .anyRequest().authenticated()
);

// 迁移后 (7.0)
http.authorizeHttpRequests(authz -> authz
    .requestMatchers("/admin/**").hasRole("ADMIN")
    .anyRequest().authenticated()
);

authorizeHttpRequests() 使用 AuthorizationManager API 而不是传统的 AccessDecisionManager

请求匹配器

移除 MvcRequestMatcher 和 AntPathRequestMatcher

MvcRequestMatcherAntPathRequestMatcher 已被移除。使用 PathPatternRequestMatcher 替代。

迁移:

java 复制代码
// 迁移前 (6.x)
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

http.authorizeHttpRequests(authz -> authz
    .requestMatchers(new AntPathRequestMatcher("/api/**")).hasRole("API")
);

// 迁移后 (7.0)
http.authorizeHttpRequests(authz -> authz
    .requestMatchers("/api/**").hasRole("API")  // 默认使用 PathPattern
);

默认的请求匹配策略现在基于 Spring 的 PathPattern,它比 Ant 样式的模式提供更好的性能和更多功能。

Jackson迁移

Spring Security 7.0 默认使用 Jackson 3。Jackson 2 支持已弃用。

更新 ObjectMapper 配置

迁移前 (Jackson 2):

java 复制代码
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.jackson2.SecurityJackson2Modules;

ObjectMapper mapper = new ObjectMapper();
mapper.registerModules(SecurityJackson2Modules.getModules(
    getClass().getClassLoader()));

迁移后 (Jackson 3):

java 复制代码
import tools.jackson.databind.json.JsonMapper;
import org.springframework.security.jackson3.SecurityJacksonModules;

JsonMapper.Builder builder = JsonMapper.builder();
SecurityJacksonModules.getModules(getClass().getClassLoader())
    .forEach(builder::addModule);
JsonMapper mapper = builder.build();

替换单个模块

迁移前 (Jackson 2):

java 复制代码
import org.springframework.security.jackson2.CoreJackson2Module;
mapper.registerModule(new CoreJackson2Module());

迁移后 (Jackson 3):

java 复制代码
import org.springframework.security.jackson3.SecurityJacksonModules;
// 使用自动模块检测
SecurityJacksonModules.getModules(getClass().getClassLoader())
    .forEach(builder::addModule);

授权服务器配置

如果使用 spring-security-oauth2-authorization-server,它现在默认使用 Jackson 3。继续使用 Jackson 2(不推荐):

Maven:

xml 复制代码
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-oauth2-authorization-server</artifactId>
    <exclusions>
        <exclusion>
            <groupId>tools.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
</dependency>

OAuth 2.0变更

JWT类型验证

Spring Security 7.0 默认验证 typ 头部。如果你在 6.5 中禁用了此功能,可以移除这些配置。

Servlet实现:

java 复制代码
// 6.5 准备 (7.0中可以移除)
@Bean
JwtDecoder jwtDecoder() {
    NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(location)
        .validateTypes(false) // ← 移除这行
        .build();
    jwtDecoder.setJwtValidator(JwtValidators.createDefaultWithValidators(
        new JwtIssuerValidator(location), 
        JwtTypeValidator.jwt())); // ← 移除显式 JwtTypeValidator
    return jwtDecoder;
}

// 7.0 (简化)
@Bean
JwtDecoder jwtDecoder() {
    NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(location)
        .build(); // validateTypes 默认为 false,包含 JwtTypeValidator
    jwtDecoder.setJwtValidator(JwtValidators.createDefaultWithIssuer(location));
    return jwtDecoder;
}

Reactive实现:

java 复制代码
// 6.5 准备 (7.0中可以移除)
@Bean
NimbusReactiveJwtDecoder jwtDecoder() {
    NimbusReactiveJwtDecoder jwtDecoder = 
        NimbusReactiveJwtDecoder.withIssuerLocation(location)
            .validateTypes(false) // ← 移除这行
            .build();
    jwtDecoder.setJwtValidator(JwtValidators.createDefaultWithValidators(
        new JwtIssuerValidator(location), 
        JwtTypeValidator.jwt())); // ← 移除显式 JwtTypeValidator
    return jwtDecoder;
}

// 7.0 (简化)
@Bean
NimbusReactiveJwtDecoder jwtDecoder() {
    NimbusReactiveJwtDecoder jwtDecoder = 
        NimbusReactiveJwtDecoder.withIssuerLocation(location)
            .build(); // validateTypes 默认为 false,包含 JwtTypeValidator
    jwtDecoder.setJwtValidator(JwtValidators.createDefaultWithIssuer(location));
    return jwtDecoder;
}

BearerTokenAuthenticationFilter配置

BearerTokenAuthenticationFilter 上的 setBearerTokenResolver()setAuthenticationDetailsSource() 方法已弃用。在 BearerTokenAuthenticationConverter 上配置这些。

迁移:

java 复制代码
// 迁移前 (6.x)
BearerTokenAuthenticationFilter filter = 
    new BearerTokenAuthenticationFilter(authenticationManager);
filter.setBearerTokenResolver(myBearerTokenResolver);
filter.setAuthenticationDetailsSource(myAuthenticationDetailsSource);

// 迁移后 (7.0)
BearerTokenAuthenticationConverter authenticationConverter = 
    new BearerTokenAuthenticationConverter();
authenticationConverter.setBearerTokenResolver(myBearerTokenResolver);
authenticationConverter.setAuthenticationDetailsSource(myAuthenticationDetailsSource);

BearerTokenAuthenticationFilter filter = 
    new BearerTokenAuthenticationFilter(authenticationManager, authenticationConverter);

移除密码授权

OAuth 2.0 密码授权已被移除,因为它不再被 OAuth 2.0 规范推荐。适当地迁移到授权码流与 PKCE 或客户端凭证流。

PKCE默认启用

使用 spring-security-oauth2-authorization-server 时,PKCE(授权码交换证明密钥)现在对所有授权码流默认启用。这提高了安全性,无需配置更改。

SAML 2.0变更

LogoutResponse行为

在 Spring Security 7.0 中,当 <saml2:LogoutRequest> 验证失败时,Spring Security 现在返回错误 <saml2:LogoutResponse> 而不是返回 HTTP 401。这符合 SAML 2.0 规范要求。

选择退出(如果需要):

java 复制代码
@Bean
Saml2LogoutResponseResolver logoutResponseResolver(
        RelyingPartyRegistrationRepository registrations) {
    OpenSaml5LogoutResponseResolver delegate = 
        new OpenSaml5LogoutResponseResolver(registrations);
    
    return new Saml2LogoutResponseResolver() {
        @Override
        public Saml2LogoutResponse resolve(HttpServletRequest request, 
                                          Authentication authentication) {
            return delegate.resolve(request, authentication);
        }

        @Override
        public Saml2LogoutResponse resolve(HttpServletRequest request, 
                                          Authentication authentication, 
                                          Saml2AuthenticationException error) {
            return null; // 恢复到 6.x 行为
        }
    };
}

AssertingPartyDetails移除

AssertingPartyDetails 类已被移除。使用 AssertingPartyMetadata 接口替代。

迁移通常涉及更新方法签名:

java 复制代码
// 迁移前 (6.x)
public void processAssertion(AssertingPartyDetails details) {
    String entityId = details.getEntityId();
    // ...
}

// 迁移后 (7.0)
public void processAssertion(AssertingPartyMetadata metadata) {
    String entityId = metadata.getEntityId();
    // ...
}

Saml2AuthenticatedPrincipal弃用

Spring Security 7.0 将断言详情与主体分离。凭证现在实现 Saml2ResponseAssertionAccessor 而不是使用 Saml2AuthenticatedPrincipal

默认行为使用 Saml2AssertionAuthentication,它自动处理此功能。

自定义实现可能需要调整:

java 复制代码
// 迁移前 (6.x)
public Authentication authenticate(Authentication authentication) {
    // ... 认证逻辑
    Saml2AuthenticatedPrincipal principal = createPrincipal(response);
    return new Saml2Authentication(principal, saml2Response, authorities);
}

// 迁移后 (7.0 - 如果使用默认)
// ResponseAuthenticationConverter 现在返回 Saml2AssertionAuthentication
// 如果使用默认设置则无需更改

// 迁移后 (7.0 - 如果自定义)
@Bean
OpenSaml5AuthenticationProvider authenticationProvider() {
    OpenSaml5AuthenticationProvider provider = 
        new OpenSaml5AuthenticationProvider();
    ResponseAuthenticationConverter defaults = 
        new ResponseAuthenticationConverter();
    
    // 包装以返回 Saml2AssertionAuthentication
    provider.setResponseAuthenticationConverter(
        defaults.andThen(authentication -> 
            new Saml2AssertionAuthentication(
                authentication.getPrincipal(),
                authentication.getSaml2Response(),
                authentication.getAuthorities()
            )
        )
    );
    return provider;
}

GET请求支持移除

Saml2AuthenticationTokenConverterOpenSaml5AuthenticationTokenConverter 默认不再处理 GET 请求,因为 SAML 2.0 规范不支持通过 GET 的 <saml2:Response>

这是推荐的行为。如果必须支持 GET 请求(不推荐),请显式启用:

java 复制代码
@Bean
OpenSaml5AuthenticationTokenConverter authenticationConverter(
        RelyingPartyRegistrationRepository registrations) {
    OpenSaml5AuthenticationTokenConverter converter = 
        new OpenSaml5AuthenticationTokenConverter(registrations);
    converter.setShouldConvertGetRequests(true); // 不推荐
    return converter;
}

需要OpenSAML 5

OpenSAML 4 支持已移除。迁移到 OpenSAML 5。

Maven:

xml 复制代码
<dependency>
    <groupId>org.opensaml</groupId>
    <artifactId>opensaml-core</artifactId>
    <version>5.0.0</version>
</dependency>
<dependency>
    <groupId>org.opensaml</groupId>
    <artifactId>opensaml-saml-api</artifactId>
    <version>5.0.0</version>
</dependency>
<dependency>
    <groupId>org.opensaml</groupId>
    <artifactId>opensaml-saml-impl</artifactId>
    <version>5.0.0</version>
</dependency>

Web安全变更

会话并发控制

SessionLimit 函数式接口提供更灵活的会话控制策略。虽然基于整数的 API 仍然支持,但函数式方法允许按用户动态会话限制。

java 复制代码
// 简单方法(仍受支持)
http.sessionManagement(session -> session
    .sessionConcurrency(concurrency -> concurrency
        .maximumSessions(1)
        .maxSessionsPreventsLogin(true)
    )
);

// 函数式方法(7.0特性)
http.sessionManagement(session -> session
    .sessionConcurrency(concurrency -> concurrency
        .maximumSessions(SessionLimit.of(authentication -> {
            // 基于用户角色的动态限制
            if (hasRole(authentication, "ADMIN")) {
                return -1; // 管理员无限制
            }
            return 1; // 普通用户限制
        }))
        .maxSessionsPreventsLogin(true)
    )
);

默认登录页面多因素支持

默认登录页面现在支持基于 factor.typefactor.reason 请求参数显示多因素认证提示。这不需要迁移但提供了增强的功能。

模块特定变更

Kerberos集成

Spring Security Kerberos 扩展现在是 Spring Security 主项目的一部分。将导入从扩展项目更新到主项目。

java 复制代码
// 迁移前 (使用扩展)
import org.springframework.security.extensions.kerberos.*;

// 迁移后 (7.0)
import org.springframework.security.kerberos.*;

Spring授权服务器

Spring授权服务器现在是Spring Security的一部分。相应更新依赖:

Maven:

xml 复制代码
<!-- 迁移前 (独立项目) -->
<dependency>
    <groupId>org.springframework.security.experimental</groupId>
    <artifactId>spring-authorization-server</artifactId>
</dependency>

<!-- 迁移后 (7.0) -->
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-oauth2-authorization-server</artifactId>
</dependency>

LDAP变更

ApacheDsContainer 和相关 Apache DS 支持已移除。使用 UnboundID 进行嵌入式 LDAP 服务器。

迁移:

xml 复制代码
<!-- 迁移前 (6.x - Apache DS) -->
<ldap-server mode="apacheds" />

<!-- 迁移后 (7.0 - UnboundID) -->
<ldap-server mode="unboundid" />

或在 Java 配置中:

java 复制代码
// 迁移后 (7.0)
@Bean
EmbeddedLdapServerContextSourceFactoryBean contextSourceFactoryBean() {
    EmbeddedLdapServerContextSourceFactoryBean factory = 
        new EmbeddedLdapServerContextSourceFactoryBean();
    factory.setPort(0); // 随机端口
    return factory;
}

测试更新

MockMvc匹配器

Spring Security 7.0 添加了新的测试工具用于验证权限:

java 复制代码
// 7.0 新增
mockMvc.perform(get("/api/resource")
    .with(user("testuser")))
    .andExpect(status().isOk())
    .andExpect(withAuthorities("ROLE_USER", "ROLE_ADMIN"));

验证和测试

完成迁移步骤后,执行以下验证:

检查清单

  • ✅ 应用程序启动时 XML 配置没有 BeanDefinitionParsingException
  • ✅ 所有安全过滤器正确注册(检查过滤器链的日志)
  • ✅ 所有配置的机制的身份验证都正常工作
  • ✅ 授权规则正确执行
  • ✅ 会话管理按预期工作
  • ✅ CSRF 保护正常工作(如果启用)
  • ✅ OAuth 2.0 流成功完成(如果适用)
  • ✅ SAML 2.0 认证和注销工作(如果适用)
  • ✅ 自定义 AuthorizationManager 实现正常工作
  • ✅ 方法安全注解正确执行
  • ✅ 集成测试通过
  • ✅ 没有已移除 API 的弃用警告

常见问题

问题 解决方案
XML schema 的 BeanDefinitionParsingException 将 schema 位置更新为 spring-security-7.0.xsd 或 spring-security.xsd
Access Decision API 的 ClassNotFoundException 添加 spring-security-access 依赖
and() 方法的编译错误 移除 and() 调用并使用 lambda DSL
Jackson 序列化失败 完成 Jackson 2 到 Jackson 3 的迁移
SAML 注销链中断 验证 Saml2LogoutResponseResolver 返回错误响应
请求匹配器错误 将 AntPathRequestMatcher/MvcRequestMatcher 替换为 PathPatternRequestMatcher

配置实体引用

关键类和接口

组件 位置 目的
SecurityNamespaceHandler config/src/main/java/org/springframework/security/config/SecurityNamespaceHandler.java 解析 XML 安全命名空间,强制执行版本要求
SpringSecurityCoreVersion core/src/main/java/org/springframework/security/core/SpringSecurityCoreVersion.java 版本检查和兼容性验证
PathPatternRequestMatcher web/src/main/java/org/springframework/security/web/util/matcher/ 替换 Ant/MVC 匹配器的默认请求匹配器
AuthorizationManager org.springframework.security.authorization.AuthorizationManager 核心授权 API
BearerTokenAuthenticationConverter org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationConverter OAuth 2.0 承载令牌处理配置
Saml2ResponseAssertionAccessor org.springframework.security.saml2.provider.service.authentication.Saml2ResponseAssertionAccessor SAML 断言访问接口
SessionLimit web/src/main/java/org/springframework/security/web/authentication/session/SessionLimit.java 会话限制的函数式接口
AssertingPartyMetadata org.springframework.security.saml2.provider.service.registration.AssertingPartyMetadata SAML 断言方配置接口

总结

Spring Security 7.0 代表了框架的重大现代化,移除了长期弃用的 API 并提高了一致性。关键迁移主题包括:

  • 授权API : 从 AccessDecisionManagerAuthorizationManager 的完全转换
  • 配置 : 移除 and() 方法,XML schema 版本要求
  • 请求匹配 : 基于 PathPatternRequestMatcher 的标准化
  • Jackson: 迁移到 Jackson 3
  • OAuth 2.0: 默认启用 PKCE 的增强安全性,移除密码授权
  • SAML 2.0: 改进的规范合规性,要求 OpenSAML 5
  • 模块架构: 集成以前独立的项目

通过遵循本指南中的步骤并使用 Spring Security 6.5 作为准备版本,你可以自信地迁移到 7.0。对于本指南未涵盖的应用程序特定迁移场景,请咨询本指南开头链接的详细迁移页面。


相关资源:

相关推荐
有一个好名字2 小时前
设计模式-代理模式
java·设计模式·代理模式
okseekw2 小时前
Java多线程开发实战:解锁线程安全与性能优化的关键技术
java·后端
Java天梯之路2 小时前
Spring Boot 钩子全集实战(三):`EnvironmentPostProcessor` 详解
java·spring
无敌最俊朗@2 小时前
STL-适配器(面试复习4)
java·面试·职场和发展
Han.miracle2 小时前
《Spring MVC 响应机制综合实践:页面、数据、JSON 与响应配置》
java·spring·springboot
zhengfei6112 小时前
漏洞情报聚合与分析工具——TL-ICScan
数据库·oracle
JHC0000002 小时前
dy直播间评论保存插件
java·后端·python·spring cloud·信息可视化
专注API从业者2 小时前
构建企业级 1688 数据管道:商品详情 API 的分布式采集与容错设计
大数据·开发语言·数据结构·数据库·分布式
SuperherRo2 小时前
JAVA攻防-FastJson专题&面试不出网利用&BCEL字节码&C3P0二次&Impl链&延时判断
java·fastjson·不出网