Spring Security 7: MFA, Modular Config, and What Breaks

Spring Security 7: MFA, Modular Config, and What Breaks

Spring Security 7 dropped at Spring I/O 2026. Daniel Erno from the Spring Security team gave a talk covering the biggest changes. Here’s what matters if you’re building Java apps with Spring Boot. Spring Security 7 在 Spring I/O 2026 大会上正式发布。来自 Spring Security 团队的 Daniel Erno 发表了演讲,涵盖了此次版本更新中的重大变更。如果你正在使用 Spring Boot 构建 Java 应用,以下内容至关重要。

Multi-Factor Authentication (MFA) — The Big One

多因素身份验证 (MFA) —— 重头戏

This feature was requested 12 years ago (issue #2603, opened November 2013). It finally shipped. What it does: You can now enforce MFA at the application level or per-endpoint. Spring Security tracks which authentication factors each user has completed and when they authenticated. 这项功能早在 12 年前(2013 年 11 月开启的 issue #2603)就被提出,如今终于正式上线。它的作用是:你现在可以在应用级别或针对特定端点强制执行 MFA。Spring Security 会追踪每个用户已完成的身份验证因素以及他们的验证时间。

Key classes: 核心类包括:

  • FactorGrantedAuthority — records what factor you used (password, one-time token, etc.) and when you used it
  • FactorGrantedAuthority — 记录你使用的验证因素(密码、一次性令牌等)及其使用时间
  • @EnableMultiFactorAuthentication — enables MFA across your app
  • @EnableMultiFactorAuthentication — 在整个应用中启用 MFA
  • AllRequiredFactorsAuthorizationManager — combine multiple MFA rules
  • AllRequiredFactorsAuthorizationManager — 组合多种 MFA 规则

Site-wide MFA example: 全站 MFA 示例:

@EnableMultiFactorAuthentication(authorities = { 
    FactorGrantedAuthority.PASSWORD_AUTHORITY, 
    FactorGrantedAuthority.OTT_AUTHORITY 
})

Now every protected endpoint requires both password login AND a one-time token. 现在,每个受保护的端点都需要同时通过密码登录和一次性令牌验证。

Per-endpoint MFA (more practical): 针对特定端点的 MFA(更具实用性):

@Bean 
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { 
    var mfa = new AllRequiredFactorsAuthorizationManager.Builder() 
        .requiredFactor(FactorGrantedAuthority.PASSWORD_AUTHORITY) 
        .requiredFactor(FactorGrantedAuthority.OTT_AUTHORITY) 
        .build(); 
    http.authorizeHttpRequests(authZ -> authZ 
        .requestMatchers("/public.html").permitAll() 
        .requestMatchers("/admin.html").access(mfa.hasRole("admin")) 
        .anyRequest().authenticated() 
    ); 
    return http.build(); 
}

Time-based rules: You can require that an authentication is recent. For example, force users to re-authenticate before changing their password: 基于时间的规则:你可以要求身份验证必须是“近期”的。例如,强制用户在修改密码前重新进行身份验证:

var recentPassword = AllRequiredFactorsAuthorizationManager.builder() 
    .requiredFactor(FactorGrantedAuthority.PASSWORD_AUTHORITY, Duration.ofMinutes(5)) 
    .build(); 
http.authorizeHttpRequests(authZ -> authZ.requestMatchers("/change-password") 
    .access(recentPassword) 
);

If a user logged in 30 minutes ago, they get redirected back to login before accessing the password change page. 如果用户是在 30 分钟前登录的,他们在访问密码修改页面前会被重定向回登录界面。

Why this matters: Before Spring Security 7, you had to implement MFA yourself or use a third-party library. Now it’s built into the framework. 为何重要:在 Spring Security 7 之前,你必须自行实现 MFA 或使用第三方库。现在,它已内置于框架中。

Modular Configuration — Stop Replacing Boot Defaults

模块化配置 —— 不再需要覆盖 Boot 默认设置

The old problem: When you created a SecurityFilterChain bean, you replaced Spring Boot’s entire security configuration. You had to manually add form login, session management, CSRF protection, and OAuth2 defaults. Miss one, and your app breaks. 旧问题:当你创建一个 SecurityFilterChain bean 时,你会替换掉 Spring Boot 的整个安全配置。你必须手动添加表单登录、会话管理、CSRF 保护和 OAuth2 默认设置。漏掉任何一个,应用就会出错。

The new way: Instead of a full SecurityFilterChain bean, provide a customizer that changes only what you need: 新方式:不再需要完整的 SecurityFilterChain bean,只需提供一个仅修改必要部分的定制器(Customizer):

// NEW: keeps Boot defaults, only changes what you need
@Bean 
Customizer<HttpSecurity> httpSecurityCustomizer() { 
    return http -> http.authorizeHttpRequests(authZ -> authZ.requestMatchers("/public.html").permitAll() ); 
}

Spring Boot’s form login, CSRF, session management, and OAuth2 Authorization Server defaults stay intact. You only customize the parts you change. Spring Boot 的表单登录、CSRF、会话管理和 OAuth2 授权服务器默认设置将保持不变。你只需定制你想要修改的部分。

Targeted customizers: You can also customize specific configurers without touching the full HTTP security: 针对性定制:你还可以定制特定的配置器,而无需触及完整的 HTTP 安全配置:

@Bean 
Customizer<OAuth2AuthorizationServerConfigurer> authServerCustomizer() { 
    return authz -> authz.oidc(oidc -> oidc.providerConfiguration(pc -> pc.claims(c -> c.claim("conference", "Spring I/O 2026")) ) ); 
}

This is cleaner. No more SecurityFilterChain beans unless you really need to override everything. 这种方式更简洁。除非你确实需要覆盖所有内容,否则不再需要定义 SecurityFilterChain bean。

What Got Removed

移除的内容

  • OAuth2 Password Grant — gone. If you’re using password grant type, migrate to authorization code. The OAuth 2.1 spec calls password grant “legacy.” Spring Security removed it from the client library.
  • OAuth2 密码授权模式 — 已移除。如果你正在使用密码授权类型,请迁移到授权码模式。OAuth 2.1 规范已将密码授权称为“遗留”模式。Spring Security 已将其从客户端库中移除。
  • and() DSL — gone. The old chain-style configuration with .and() is removed. Use lambdas instead. Open Rewrite can automate this migration for you.
  • and() DSL — 已移除。旧的链式配置 .and() 已被移除,请改用 Lambda 表达式。Open Rewrite 可以为你自动完成此迁移。
  • Module reorganization: AccessDecisionVoterManager moved to spring-security-access package. Kerberos and Authorization Server modules now share the same version number (7.x).
  • 模块重组AccessDecisionVoterManager 已移动到 spring-security-access 包中。Kerberos 和 Authorization Server 模块现在共享相同的版本号 (7.x)。

OAuth2 Changes

OAuth2 变更

  • PKCE is now the default. The Authorization Server enforces Proof Key for Code Exchange. Clients must send a code challenge. If you have legacy clients that can’t support PKCE, you can turn it off.
  • PKCE 现在是默认设置。 授权服务器强制要求使用代码交换证明密钥 (PKCE)。客户端必须发送代码质询。如果你有不支持 PKCE 的遗留客户端,可以将其关闭。
  • Dynamic Client Registration. Authorization Servers can now register clients through a REST endpoint (/oauth2/register). This was added mainly for MCP (Model Context Protocol) support, where AI tools like Claude Desktop need to dynamically register themselves as clients.
  • 动态客户端注册。 授权服务器现在可以通过 REST 端点 (/oauth2/register) 注册客户端。此功能主要为了支持 MCP(模型上下文协议),例如 Claude Desktop 等 AI 工具需要动态注册为客户端。

Warning: Don’t open this endpoint without access control. The spec authors recommend authenticated registration, not open registration. Open registration is a denial-of-service risk. 警告:请勿在没有访问控制的情况下开放此端点。规范作者建议使用经过身份验证的注册,而非开放注册。开放注册存在拒绝服务攻击的风险。

HTTP Service Clients with OAuth2

带有 OAuth2 的 HTTP 服务客户端

Spring Framework 7 introduced HTTP Service Clients (declarative, interface-based HTTP clients). Spring Security 7 adds OAuth2 token injection support. Spring Framework 7 引入了 HTTP 服务客户端(声明式、基于接口的 HTTP 客户端)。Spring Security 7 增加了对 OAuth2 令牌注入的支持。