• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
打工人丶
博客园    首页    新随笔    联系   管理    订阅  订阅

SpringSecurity6详解

1. SpringSecurity6

前言:本文将基于Spring Boot 3.x依赖的Spring Security 6.x版本作为讲解。Spring Boot3.X是2022年11月正式发布的
因为Spring Boot2.x是依赖的Spring Security5.x,且5.x的security与6.x的变化较大【6.x引入了很多破坏性的更新,包括废弃代码的删除,方法重命名,全新的配置DSL等】。so,本文应运而生。


SpringSecurity:是一个高度自定义的安全框架,为系统提供了声明式安全访问控制功能,减少了为系统安全而编写大星重复代码的工作。

本质:是一个过滤器链,由多个过滤器组成。



1.1 回顾过滤器链

过滤器链:指的是将多个过滤器按照一定的顺序组织起来,确保它们能够按需执行。


我们演示一下springboot整合过滤器链。

//  配置的方式
public class LoggingFilter implements Filter {  

    @Override  
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {  
        System.out.println("进入日志过滤器...");  
        // 逻辑处理(例如记录请求信息)  
        chain.doFilter(request, response);  
        System.out.println("离开日志过滤器...");  
    }  
}  

@Configuration  
public class FilterConfig {  

    @Bean
    public FilterRegistrationBean<Filter> getFilterRegistrationBean() {
		FilterRegistrationBean<Filter> filterRegistrationBean = new FilterRegistrationBean<>();
        filterRegistrationBean.setFilter(new LoggingFilter());
        filterRegistrationBean.setOrder(1); // 用于指定过滤器的优先级
        filterRegistrationBean.addUrlPatterns("/user/*");
        filterRegistrationBean.setName("filter1");
        return filterRegistrationBean;
    }

    // 如果有多个过滤器,则在后面继续注册
    @Bean
    public FilterRegistrationBean<Filter> getFilterRegistrationBean() {
    }
}  


//////////////////////////////////////////////////////////////////


// 注解的方式   直接用@Order注解给多个过滤器加上,实现过滤器链的效果
@Component  
@Order(1) // 第一优先级
@WebFilter(urlPatterns = "/api/*") // 只对 /api/* 路径下的请求生效    
public class FirstFilter implements Filter {  
    @Override  
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {  
        System.out.println("First Filter");  
        chain.doFilter(request, response);  
    }  
}  

@Component  
@Order(2) // 第二优先级  
@WebFilter(urlPatterns = "/api/*") // 只对 /api/* 路径下的请求生效  
public class SecondFilter implements Filter {  
    @Override  
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {  
        System.out.println("Second Filter");  
        chain.doFilter(request, response);  
    }  
}  


//////////////////////////////////////////////////////////////////


// 使用 FilterChain 的方法可以显式地按顺序调用多个过滤器。
public class CustomFilterChain implements Filter {  
    private final List<Filter> filters;  

    public CustomFilterChain() {  
        this.filters = new ArrayList<>();  
        this.filters.add(new FirstFilter());  
        this.filters.add(new SecondFilter());  
    }  

    @Override  
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {  
        FilterChain currentChain = chain;  
        for (Filter filter : filters) {  
            currentChain = new CustomFilterChainWrapper(currentChain, filter);  
        }  
        currentChain.doFilter(request, response);  
    }  
}  



2. SpringSecurity6与SpringSecurity5重大区别



2.1 gh-11923-移除WebSecurityConfigurerAdapter。使用SecurityFilterChain bean方式来代替

为什么这样做,springsecurity有解释:


这一条改变直接影响了 springboot2.x整合springsecurity5.x时的实现方式,WebSecurityConfigurerAdapter 被移除后,作为替代,我们需要创建类型为SecurityFilterChain的bean。


先来回顾5.x的写法:

/**
 *          WebSecurityConfigurerAdapter:继承该类是为了通过重写SpringBoot对SpringSecurity的默认配置。
 *              它提供了一些方法,您可以重写这些方法来定义安全规则、配置身份验证和授权方式,以及定制其他与安全相关的行为。
 *
 *          常用方法:(我们重写这些方法,就能调整security的默认配置)
 *              configure(HttpSecurity http): 这是最重要的方法之一,用于配置如何通过拦截器保护HTTP请求。您可以定义哪些URL路径需要特定的安全配置,例如要求身份验证、授权规则和访问权限等。
 *              configure(AuthenticationManagerBuilder auth): 这个方法用于配置身份验证机制。您可以定义用户存储的位置、身份验证规则以及密码编码器等。
 *              configure(WebSecurity web): 这个方法用于配置Spring Security忽略特定的静态资源,例如CSS、JavaScript文件或其他不需要身份验证的静态资源。
 *              userDetailsService(): 这个方法返回一个UserDetailsService对象,用于从数据库或其他数据源加载用户信息。
 **/
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
	
	@Resource
	private UserDetailsService userDetailsService;
	
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		// http.formLogin() 是Spring Security中用于配置基于表单的身份验证的方法。
		// 常用方法如下:(还有很多方法,自己写的时候通过 .方法 查看)
				// loginPage(String loginPage):                                  指定登录页面的URL。如果不指定,则默认为/login
				// loginProcessingUrl(String loginProcessingUrl):                指定登录表单提交的URL。默认为/login(也就是我们的Controller地址)
				// usernameParameter(String usernameParameter):                  指定登录表单中用户名字段的参数名。默认为username,如果你的表单提交的用户名密码不是这个,你就需要来特地指定
				// passwordParameter(String passwordParameter):                  指定登录表单中密码字段的参数名。默认为password,如果你的表单提交的用户名密码不是这个,你就需要来特地指定
				// defaultSuccessUrl:                                            登录成功后的访问地址,注意:该方法只有当用户从登录页登录的时候才生效。如果用户没登陆,去访问一个需要登录后才能访问的页面,导致被跳转到登录页,此时从登录页登录进来就不生效了。
				// successForwardUrl:                                            登录成功后的转发地址,全局生效,他就能解决上面那个问题。
				// successForwardHandler:                                        登陆成功的处理逻辑,需要传一个Handler对象(这个方法允许开发人员使用自定义的 AuthenticationSuccessHandler 来处理用户成功登录后的行为,自定义类实现相关接口,重写方法。)
				// failureUrl(String failureUrl):                                指定登录失败后的跳转页面。默认为/login?error
				// failureHandler(AuthenticationFailureHandler failureHandler):  指定自定义的登录失败处理器
				// successForwardUrl(String successUrl):                         指定登录成功后的跳转页面。默认为/login?error
				// successHandler(AuthenticationSuccessHandler successHandler):  指定自定义的登录成功处理器
				// and():                                                        用于连接其他配置方法
				// permitAll():                                                  允许所有用户访问登录页面和登录处理URL
		http.formLogin()
			.loginPage("/login.html")
			.loginProcessingUrl("/login")//指定登录访问路径(登录页面的form表单提交路径,注意必须一致,我的login.html里面写的提交路径是/login,所以这里我也写/login)
			.defaultSuccessUrl("/index.html")
			.failureUrl("/error.html");//指定用户名或密码错误访问的页面
	}
}

再来看看现在6.x的写法:

/**
 * 5版本只需@Configuration一个注解,不需要@EnableWebSecurity,
 * 6需要同时引入,并且5是需要extends WebSecurityConfigurerAdapter类
 */
@EnableWebSecurity
@Configuration
public class SecurityConfiguration {

    // 在springsecurity6.x中,推荐注册一个 SecurityFilterChain bean 的方式来实现,这更符合springboot基于组件开发的特点。
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        // 6.x支持了lambda表达式写法
        http
            .authorizeHttpRequests((authz) -> authz
                .anyRequest().authenticated()
            )
            .httpBasic(withDefaults());
        return http.build();
    }

}


2.2 移除and


先来回顾5.x的写法:

// 5.x你可以使用and()方法,用于做连接其他配置方法, 你也可以不用。   

// 用的写法如下:
@Override
public void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests().anyRequest().authenticated() // authorizeRequests() 是Spring Security中用于配置请求权限的方法。
            .and()
            .formLogin().loginPage("/login.html")    // formLogin() 是Spring Security中用于配置基于表单的身份验证的方法。
            .and()
            .csrf().disable()    // csrf() 是Spring Security中用于处理csrf的方法。
}

// 不用的写法如下:
@Override
public void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests().anyRequest().authenticated(); // authorizeRequests() 是Spring Security中用于配置请求权限的方法。
    
    http.formLogin().loginPage("/login.html")    // formLogin() 是Spring Security中用于配置基于表单的身份验证的方法。
    
    http.csrf().disable()    // csrf() 是Spring Security中用于处理csrf的方法。
}

再来看看现在6.x的写法:

// and()方法 已被移除!    当然你还可以5.x那种不用and的方法也可以,或者采用6.x推荐的lambda这种形式。
@Configuration
@EnableWebSecurity
public class MySecurityConfig {
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        return http.authorizeHttpRequests(conf -> conf.requestMatchers("/login", "/info").permitAll().anyRequest().authenticated())
                .addFilterBefore(new JwtFilter(), UsernamePasswordAuthenticationFilter.class)
                .csrf(withDefaults())
                .cors(withDefaults()).build();
    }
  
}

总而言之,言而总之。相较于5.x,6.x的改动。是对之前SpringBoot整合SpringSecurity的代码写法的一次较大改动。



3. 开始走进SpringSecurity6

3.1 获取SpringSecurity6

只要导入了依赖,其实就已经把SpringSecurity整合到你的springboot项目了。
此时,你可以试着点击一个请求,看看会发生什么。如果你没有凭证的情况下发起一个请求,会得到401的错误提示!

<dependencies>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-security</artifactId>
	</dependency>
</dependencies>

3.2 看看SpringBoot是怎么自动装配的SpringSecurity

怎么导入了一个依赖后,springsecurity就掌管了我们的springboot项目了呢?【这里因为springboot的自动配置功能实现的】

posted @ 2025-03-11 04:24  &emsp;不将就鸭  阅读(553)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3