当前位置: 首页 > article >正文

Spring Security 7 来啦

官网地址:https://docs.spring.io/spring-security/reference/migration-7/configuration.html
在这里插入图片描述

Spring Security 7 引入了一些变化,尤其是在配置方式和注解的使用上。在 Spring Security 7 中,一些 API 和方法被移除了,新的方式加入了更多的 Java Config 支持。以下是一些主要的变更和改进,以及基于 Spring Security 7 的配置示例。

  1. SecurityConfigurerAdapter 被弃用
    SecurityConfigurerAdapter 在 Spring Security 7 中被弃用了,推荐使用 SecurityConfigurer 或直接通过 SecurityConfigurerAdapter 的子类来配置。

  2. HttpSecurity 配置
    在 Spring Security 7 中,对 HttpSecurity 的配置方式发生了一些变化,特别是在 formLogin(), httpBasic(), csrf() 等配置上。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable()  // CSRF 保护禁用(取决于需求)
            .authorizeRequests()
                .antMatchers("/public/**").permitAll()  // 公开路径不需要认证
                .anyRequest().authenticated()  // 其他路径需要认证
            .and()
            .formLogin()  // 启用表单登录
                .loginPage("/login")  // 自定义登录页面
                .permitAll()  // 允许所有人访问登录页面
            .and()
            .logout()  // 启用登出功能
                .permitAll();  // 允许所有人访问登出
    }
}
  1. AuthenticationManager 配置
    Spring Security 7 中的 AuthenticationManager 配置方式与以前略有不同,Spring 7 中推荐使用 AuthenticationManagerBuilder 或直接在 SecurityFilterChain 中定义。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/public/**").permitAll()
                .anyRequest().authenticated()
            .and()
            .formLogin()
            .permitAll()
            .and()
            .logout()
            .permitAll();

        return http.build();
    }

    @Bean
    public AuthenticationManager authenticationManager(HttpSecurity http) throws Exception {
        AuthenticationManagerBuilder authenticationManagerBuilder = http.getSharedObject(AuthenticationManagerBuilder.class);
        authenticationManagerBuilder
            .inMemoryAuthentication()
                .withUser(User.withUsername("user").password("{noop}password").roles("USER"))
                .withUser(User.withUsername("admin").password("{noop}admin").roles("ADMIN"));

        return authenticationManagerBuilder.build();
    }
}
  1. 授权表达式支持
    在 Spring Security 7 中,授权表达式(如 .hasRole(), .hasAuthority())被优化并可以在 HttpSecurity 中使用。
http
    .authorizeRequests()
        .antMatchers("/admin/**").hasRole("ADMIN")  // 仅管理员可以访问
        .antMatchers("/user/**").hasRole("USER")  // 用户角色可以访问
        .anyRequest().authenticated()
    .and()
    .formLogin().permitAll();
  1. 异常处理和错误页面
    Spring Security 7 提供了对错误页面和异常处理的更好的支持,可以使用 exceptionHandling() 配置来处理异常。
http
    .exceptionHandling()
        .accessDeniedPage("/403");  // 自定义403错误页面

  1. 基于 JWT 的认证
    Spring Security 7 进一步加强了对 JWT(JSON Web Token)的支持。可以通过 BearerTokenAuthenticationFilter 来处理 JWT 认证。
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .authorizeRequests()
                .antMatchers("/api/public/**").permitAll()
                .anyRequest().authenticated()
            .and()
            .addFilter(new JWTAuthenticationFilter(authenticationManager()));  // 添加 JWT 认证过滤器
    }
}

Spring Security 7 的变化更多是围绕 Java 配置、内存用户存储和更灵活的认证机制,通常来说,它让开发者能够更方便地进行安全配置。

要深入理解 Spring Security 7,我们可以从几个关键领域探讨,包括 自定义身份验证流程、基于 JWT 的认证、授权机制的扩展、跨站请求伪造(CSRF)防护机制、OAuth2 的集成等。以下是一些进阶话题:

  1. 自定义认证流程
    在 Spring Security 7 中,你可以完全自定义认证流程,特别是通过实现 AuthenticationProvider 和 AuthenticationManager 来定义自己的认证逻辑。

示例:自定义 AuthenticationProvider
AuthenticationProvider 负责验证用户身份。你可以根据需求自定义验证逻辑。

import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;

public class CustomAuthenticationProvider implements AuthenticationProvider {

    private final UserDetailsService userDetailsService;

    public CustomAuthenticationProvider(UserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String username = authentication.getName();
        String password = authentication.getCredentials().toString();

        // 自定义认证逻辑,例如调用数据库验证
        User user = (User) userDetailsService.loadUserByUsername(username);

        if (user == null || !user.getPassword().equals(password)) {
            throw new BadCredentialsException("Authentication failed for user: " + username);
        }

        return new UsernamePasswordAuthenticationToken(user, password, user.getAuthorities());
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
    }
}

注册 AuthenticationProvider

@Bean
public AuthenticationManager authenticationManager(HttpSecurity http) throws Exception {
    AuthenticationManagerBuilder authenticationManagerBuilder = http.getSharedObject(AuthenticationManagerBuilder.class);
    authenticationManagerBuilder.authenticationProvider(new CustomAuthenticationProvider(userDetailsService()));
    return authenticationManagerBuilder.build();
}
  1. JWT 认证机制
    Spring Security 7 对 JWT 的支持也非常强大。你可以通过自定义过滤器来实现基于 JWT 的认证。

JWT 认证流程
用户通过登录获取 JWT。
后续每次请求,客户端会在 HTTP 头部传递 JWT(Authorization: Bearer )。
Spring Security 使用 JWTAuthenticationFilter 来验证该 token。

JWT 过滤器

import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.io.IOException;

public class JWTAuthenticationFilter extends OncePerRequestFilter {

    private final AuthenticationManager authenticationManager;

    public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        
        String token = extractToken(request);

        if (token != null && validateToken(token)) {
            String username = getUsernameFromToken(token);
            UsernamePasswordAuthenticationToken authenticationToken =
                    new UsernamePasswordAuthenticationToken(username, null, null);
            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        }
        filterChain.doFilter(request, response);
    }

    private String extractToken(HttpServletRequest request) {
        String header = request.getHeader("Authorization");
        if (header != null && header.startsWith("Bearer ")) {
            return header.substring(7);  // 获取 token
        }
        return null;
    }

    private boolean validateToken(String token) {
        // 使用 JWT 库(如 JJWT 或 JWTDecoder)来验证 token 是否有效
        return true;
    }

    private String getUsernameFromToken(String token) {
        // 解析 token 获取用户名
        return "username";
    }
}

将 JWTAuthenticationFilter 集成到 SecurityFilterChain 中

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
        .csrf().disable()
        .authorizeRequests()
            .antMatchers("/api/public/**").permitAll()
            .anyRequest().authenticated()
        .and()
        .addFilterBefore(new JWTAuthenticationFilter(authenticationManager()), UsernamePasswordAuthenticationFilter.class);

    return http.build();
}
  1. 授权扩展机制
    Spring Security 提供了多种方法来扩展其授权机制,包括基于角色的权限控制和基于属性的权限控制。

基于角色的授权

http
    .authorizeRequests()
        .antMatchers("/admin/**").hasRole("ADMIN")  // 仅管理员可以访问
        .antMatchers("/user/**").hasAnyRole("USER", "ADMIN")  // 用户或管理员都可以访问
        .anyRequest().authenticated()
    .and()
    .formLogin().permitAll();

基于权限(hasPermission())的授权
Spring Security 允许通过权限(如 hasPermission())来实现更加细粒度的控制。

http
    .authorizeRequests()
        .antMatchers("/admin/**").hasPermission("ADMIN_ACCESS")
        .antMatchers("/user/**").hasPermission("USER_ACCESS")
        .anyRequest().authenticated()
    .and()
    .formLogin().permitAll();
  1. CSRF 防护
    Spring Security 默认启用了 CSRF 防护,但是在一些无状态(stateless)应用(例如基于 JWT 的应用)中,你可能会禁用它。

启用/禁用 CSRF
启用 CSRF:Spring Security 会自动生成一个 CSRF token,并验证每个请求中的 token。

http
    .csrf()
        .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()); // 使用 cookie 存储 token

禁用 CSRF:对于 REST API 或基于 JWT 的应用,通常禁用 CSRF。

http
    .csrf().disable();

  1. OAuth2 集成
    Spring Security 7 进一步改进了对 OAuth2 的集成,提供了更简洁的方式来进行 OAuth2 客户端配置。

OAuth2 客户端配置

@Configuration
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/login/oauth2/**").permitAll()
                .anyRequest().authenticated()
            .and()
            .oauth2Login();  // 启用 OAuth2 登录
        return http.build();
    }
}

OAuth2 资源服务器配置
如果你的应用作为 OAuth2 资源服务器(API 端点),你可以使用以下配置来验证 OAuth2 Access Token:

@Configuration
@EnableWebSecurity
public class OAuth2ResourceServerConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .anyRequest().authenticated()
            .and()
            .oauth2ResourceServer()
                .jwt();  // 配置 JWT 验证
        return http.build();
    }
}

Spring Security 7 提供了更强大、灵活且可扩展的认证与授权机制。通过自定义认证提供者、JWT 认证、OAuth2 集成等方式,可以轻松满足各种复杂的安全需求。如果你的应用涉及到特定的认证需求(如集成第三方认证或微服务中的统一认证),Spring Security 7 提供了更多的配置选项和扩展点。

Spring Security 7.0 版本的一个重要变化是完全移除了传统的链式配置(WebSecurityConfigurerAdapter 配置方式),而转向了全新的基于 Lambda 表达式的配置方式(Lambda DSL),这是一种更加简洁且灵活的方式来配置安全设置。Spring Security 7 采用了新的 API 设计,以便让开发者通过 Lambda 表达式更直观地进行配置。

在 Spring Security 7 之前,安全配置通常使用 WebSecurityConfigurerAdapter 类和 HttpSecurity 的链式方法来配置安全策略。但在 7.0 中,WebSecurityConfigurerAdapter 被弃用,并且很多配置方法都发生了变化。

新的 Lambda DSL 配置方式
Spring Security 7.0 推荐使用 SecurityFilterChain 配合 HttpSecurity 配置进行替代。
基本配置结构
传统的 WebSecurityConfigurerAdapter 配置方式:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/login", "/public/**").permitAll()
                .anyRequest().authenticated()
            .and()
            .formLogin()
                .loginPage("/login")
                .permitAll()
            .and()
            .logout()
                .permitAll();
    }
}

新的 Lambda DSL 配置方式
Spring Security 7 推荐通过 SecurityFilterChain Bean 来配置安全策略,结合 HttpSecurity 使用 Lambda 风格的 API:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeRequests(authz -> authz
                .antMatchers("/login", "/public/**").permitAll()
                .anyRequest().authenticated())
            .formLogin(form -> form
                .loginPage("/login")
                .permitAll())
            .logout(logout -> logout
                .permitAll());
        return http.build();
    }
}

关键变化说明
SecurityFilterChain Bean:

在新的配置方式中,Spring Security 使用 SecurityFilterChain Bean 来定义安全策略。
http.build() 语法构建最终的 SecurityFilterChain 实例。
Lambda 表达式的使用:

authorizeRequests(), formLogin(), logout() 等配置方法都使用了 Lambda 表达式,使得代码更加简洁,且配置更具可读性。
@EnableWebSecurity:

@EnableWebSecurity 注解依然有效,告诉 Spring 启用 Web 安全功能,但不再需要扩展 WebSecurityConfigurerAdapter。
使用新的 Lambda DSL 的好处
更简洁和直观:不再需要继承和重写方法,而是直接使用 Lambda 表达式来配置。
灵活性:支持按需定制的安全配置,尤其适合微服务架构中的复杂安全需求。
减少样板代码:避免了传统方式中必须创建 WebSecurityConfigurerAdapter 类的样板代码,开发者可以直接在配置类中定义 SecurityFilterChain。
高级配置示例:基于角色的授权
如果需要进行更复杂的授权配置,如基于角色的授权,仍然可以轻松实现:

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
        .authorizeRequests(authz -> authz
            .antMatchers("/admin/**").hasRole("ADMIN")
            .antMatchers("/user/**").hasRole("USER")
            .anyRequest().authenticated())
        .formLogin(form -> form
            .loginPage("/login")
            .permitAll())
        .logout(logout -> logout
            .permitAll());
    return http.build();
}

高级配置示例:自定义认证和 JWT 认证
对于更复杂的认证逻辑,如 JWT 认证,仍然可以通过 Lambda DSL 来进行配置。

示例:基于 JWT 的认证配置

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
        .csrf().disable()
        .authorizeRequests(authz -> authz
            .antMatchers("/public/**").permitAll()
            .anyRequest().authenticated())
        .addFilterBefore(new JWTAuthenticationFilter(authenticationManager()), UsernamePasswordAuthenticationFilter.class)
        .formLogin().disable();  // 如果使用 JWT 则禁用表单登录
    return http.build();
}

SecurityFilterChain 和 HttpSecurity 的兼容性
SecurityFilterChain 是一个函数式接口,它通过 Lambda 表达式支持配置多个 HTTP 安全策略。
HttpSecurity 的配置方法(如 authorizeRequests(), formLogin(), logout() 等)依然保留,并且支持 Lambda 风格的 API,提供了更为灵活的配置方式。
结论
Spring Security 7 完全移除了传统的 WebSecurityConfigurerAdapter 类,推荐开发者使用全新的 Lambda DSL 配置方式。通过这种方式,安全配置更加简洁、灵活,并且符合现代 Java 配置的标准,能够有效减少样板代码,同时提升可维护性。

通过这次的变更,Spring Security 更加注重“声明式配置”而非“继承式配置”,让开发者能够用更加直观的方式定制安全策略。如果你有更复杂的安全需求,新的 Lambda DSL 让扩展更加简单和灵活。

通俗易懂的来啦

Spring Security 7 中的 Lambda DSL 配置

  1. 简化配置:
    在 Spring Security 7 中,使用 Lambda 表达式来配置 HTTP 安全性。这种方式更加简洁,易于理解,避免了传统配置中需要链式调用 .and() 的复杂性。
@Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(authorize -> authorize
                .requestMatchers("/blog/**").permitAll() // 允许所有访问博客页面
                .anyRequest().authenticated()  // 其他请求都需要认证
            )
            .formLogin(formLogin -> formLogin
                .loginPage("/login")  // 自定义登录页面
                .permitAll()  // 允许所有用户访问登录页面
            )
            .rememberMe(Customizer.withDefaults());  // 开启“记住我”功能
        return http.build();
    }
}

  1. 与传统配置方式的比较:
    传统方式: 使用链式调用的方式来配置(例如 .and())。
http
    .authorizeHttpRequests()
        .requestMatchers("/blog/**").permitAll()
        .anyRequest().authenticated()
    .and()
    .formLogin()
        .loginPage("/login")
        .permitAll()
    .and()
    .rememberMe();

Lambda DSL: 不再需要 .and() 方法,代码更加直观和简洁。
3. 自动化缩进:
Lambda DSL 的一个重要优势是自动的缩进和结构化,这使得配置更加可读和易于理解。

  1. Customizer.withDefaults():
    这个方法是 Spring Security 提供的一个快捷方式,用于启用默认的配置。例如,在启用 rememberMe 功能时,使用 Customizer.withDefaults() 会自动配置默认行为,而无需手动定义每个参数。

  2. WebFlux 的配置:
    WebFlux 安全配置也可以采用类似的 Lambda DSL 风格:

@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {

    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
        http
            .authorizeExchange(exchanges -> exchanges
                .pathMatchers("/blog/**").permitAll()
                .anyExchange().authenticated()
            )
            .httpBasic(Customizer.withDefaults())
            .formLogin(formLogin -> formLogin
                .loginPage("/login")
            );
        return http.build();
    }
}
  1. 自定义 DSL 的更新:
    在 Spring Security 6.2 之后,HttpSecurity#apply() 方法已被弃用,并且计划在 Spring Security 7 中删除。推荐使用 .with() 方法来配置自定义 DSL,这会使配置更清晰和一致。
http.with(customSecurityDsl -> customSecurityDsl.configure(http));

Lambda DSL 的目标和优势
提高可读性: 自动缩进让配置更易读。
减少冗余: 不再需要 .and() 来进行配置链式调用。
一致性: Lambda DSL 使得 Spring Security 的配置风格与其他 Spring 项目(如 Spring Integration、Spring Cloud Gateway)保持一致。
简化自定义 DSL: 自定义 DSL 配置变得更加直观,避免了链式调用的复杂性。
Spring Security 7 引入的 Lambda DSL 极大地简化了配置过程,提升了代码的可读性和一致性。从 Spring Security 6.2 开始,这种配置方式已经成为标准,并且将成为未来的推荐方式。对于新项目,建议立即采用这种方式配置 Spring Security。


http://www.kler.cn/a/514412.html

相关文章:

  • Kubernetes 集群中安装和配置 Kubernetes Dashboard
  • 深度学习中Batch Normalization(BN)原理、作用浅析
  • Node.js 完全教程:从入门到精通
  • Mysql触发器(学习自用)
  • 1170 Safari Park (25)
  • iOS UIScrollView的一个特性
  • HTB:Remote[WriteUP]
  • AR智慧点巡检系统探究和技术方案设计
  • 微软 Win11 RP 22631.4825(KB5050092)预览版发布!
  • 哈夫曼树(构建、编码、译码)(详细分析+C++代码实现)
  • 纯前端实现表格中的数据导出功能-使用xlsx和file-saver
  • 【大数据】机器学习----------计算机学习理论
  • OpenHarmony OTA升级参考资料记录
  • 路由重分布
  • Hack The Box-Starting Point系列Vaccine
  • 【机器学习实战中阶】使用SARIMAX,ARIMA预测比特币价格,时间序列预测
  • LINUX下设置分离状态(Detached State)和未设置分离状态的主要区别在于线程资源的管理方式和线程的生命周期。以下是两种状态的对比:
  • 1.21学习
  • Ceisum无人机巡检直播视频投射
  • SpringCloud学习笔记【尚硅谷2024版】
  • 2025年1月19日(舵机VCC)
  • vue3切换路由后页面不报错显示空白,刷新后显示正常
  • 鸿蒙产业学院正式揭牌!软通动力与深信息签署校企合作框架协议
  • Postgresql源码(141)JIT系列分析汇总
  • HDFS的Shell操作
  • 【愚公系列】《微信小程序与云开发从入门到实践》059-迷你商城小程序的开发(加入购物车与创建订单功能开发)