Spring Security(二)--WebSecurityConfigurer配置以及filter顺序

简介: 在认证过程和访问授权前必须了解spring Security如何知道我们要求所有用户都经过身份验证? Spring Security如何知道我们想要支持基于表单的身份验证?因此必须了解WebSecurityConfigurerAdapter配置类如何工作的。而且也必须了解清楚filter的顺序,才能更好了解其调用工作流程。

在认证过程和访问授权前必须了解spring Security如何知道我们要求所有用户都经过身份验证? Spring Security如何知道我们想要支持基于表单的身份验证?因此必须了解WebSecurityConfigurerAdapter配置类如何工作的。而且也必须了解清楚filter的顺序,才能更好了解其调用工作流程。


1. WebSecurityConfigurerAdapter


在使用WebSecurityConfigurerAdapter前,先了解Spring security config。


Spring security config具有三个模块,一共有3个builder,认证相关的AuthenticationManagerBuilder和web相关的WebSecurity、HttpSecurity。


  1. AuthenticationManagerBuilder:用来配置全局的认证相关的信息,其实就是AuthenticationProvider和UserDetailsService,前者是认证服务提供商,后者是用户详情查询服务;
  2. WebSecurity: 全局请求忽略规则配置(比如说静态文件,比如说注册页面)、全局HttpFirewall配置、是否debug配置、全局SecurityFilterChain配置、privilegeEvaluator、expressionHandler、securityInterceptor;
  3. HttpSecurity:具体的权限控制规则配置。一个这个配置相当于xml配置中的一个标签。各种具体的认证机制的相关配置,OpenIDLoginConfigurer、AnonymousConfigurer、FormLoginConfigurer、HttpBasicConfigurer等。


WebSecurityConfigurerAdapter提供了简洁方式来创建WebSecurityConfigurer,其作为基类,可通过实现该类自定义配置类,主要重写这三个方法:


protected void configure(AuthenticationManagerBuilder auth) throws Exception {}
 public void configure(WebSecurity web) throws Exception {}
 protected void configure(HttpSecurity httpSecurity) throws Exception {}
复制代码


而且其自动从SpringFactoriesLoader查找AbstractHttpConfigurer让我们去扩展,想要实现必须创建一个AbstractHttpConfigurer的扩展类,并在classpath路径下创建一个文件META-INF/spring.factories。例如:


org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer = sample.MyClassThatExtendsAbstractHttpConfigurer


其源码分析:


//1.init初始化:获取HttpSecurity和配置FilterSecurityInterceptor拦截器到WebSecurity
 public void init(final WebSecurity web) throws Exception {
         //获取HttpSecurity
    final HttpSecurity http = getHttp();
  //配置FilterSecurityInterceptor拦截器到WebSecurity
     web.addSecurityFilterChainBuilder(http).postBuildAction(new Runnable() {
      public void run() {
        FilterSecurityInterceptor securityInterceptor = http
            .getSharedObject(FilterSecurityInterceptor.class);
        web.securityInterceptor(securityInterceptor);
      }
     });
 }
 ......
 //2.获取HttpSecurity的过程
 protected final HttpSecurity getHttp() throws Exception {
 if (http != null) {
  return http;
 }
 DefaultAuthenticationEventPublisher eventPublisher = objectPostProcessor
    .postProcess(new DefaultAuthenticationEventPublisher());
 localConfigureAuthenticationBldr.authenticationEventPublisher(eventPublisher);
 AuthenticationManager authenticationManager = authenticationManager();
 authenticationBuilder.parentAuthenticationManager(authenticationManager);
 Map<Class<? extends Object>, Object> sharedObjects = createSharedObjects();
 http = new HttpSecurity(objectPostProcessor, authenticationBuilder,
    sharedObjects);
 if (!disableDefaults) {
  // 默认的HttpSecurity的配置
  http
                 //添加 CSRF 支持,使用WebSecurityConfigurerAdapter时,默认启用,禁用csrf().disable()
    .csrf().and() 
    //添加WebAsyncManagerIntegrationFilter
    .addFilter(new WebAsyncManagerIntegrationFilter())
    //允许配置异常处理
    .exceptionHandling().and()
    //将安全标头添加到响应
    .headers().and()
    //允许配置会话管理
    .sessionManagement().and()
    //HttpServletRequest之间的SecurityContextHolder创建securityContext管理
    .securityContext().and()
    //允许配置请求缓存
    .requestCache().and()
    //允许配置匿名用户
    .anonymous().and()
    //HttpServletRequestd的方法和属性注册在SecurityContext中
    .servletApi().and()
    //使用默认登录页面
    .apply(new DefaultLoginPageConfigurer<>()).and()
    //提供注销支持
    .logout();
  // @formatter:on
  ClassLoader classLoader = this.context.getClassLoader();
  List<AbstractHttpConfigurer> defaultHttpConfigurers =
      SpringFactoriesLoader.loadFactories(AbstractHttpConfigurer.class, classLoader);
  for(AbstractHttpConfigurer configurer : defaultHttpConfigurers) {
    http.apply(configurer);
  }
 }
 configure(http);
 return http;
 }
 ...
 //3.可重写方法实现自定义的HttpSecurity   
 protected void configure(HttpSecurity http) throws Exception {
 logger.debug("Using default configure(HttpSecurity). If subclassed this will potentially override subclass configure(HttpSecurity).");
 http
  .authorizeRequests()
    .anyRequest().authenticated()
    .and()
  .formLogin().and()
  .httpBasic();
 }
 ....
复制代码


从源码init初始化模块中的“获取HttpSecurity”和“配置FilterSecurityInterceptor拦截器到WebSecurity”中可以看出,想要spring Security如何知道我们要求所有用户都经过身份验证? Spring Security如何知道我们想要支持基于表单的身份验证?只要重写protected void configure(HttpSecurity http) throws Exception方法即可。因此我们需要理解HttpSecurity的方法的作用,如何进行配置。下一节来讨论HttpSecurity。


2. HttpSecurity


HttpSecurity基于Web的安全性允许为特定的http请求进行配置。其有很多方法,列举一些常用的如下表:


方法 说明 使用案例
csrf() 添加 CSRF 支持,使用WebSecurityConfigurerAdapter时,默认启用 禁用:csrf().disable()
openidLogin() 用于基于 OpenId 的验证 openidLogin().permitAll();
authorizeRequests() 开启使用HttpServletRequest请求的访问限制 authorizeRequests().anyRequest().authenticated()
formLogin() 开启表单的身份验证,如果未指定FormLoginConfigurer#loginPage(String),则将生成默认登录页面 formLogin().loginPage("/authentication/login").failureUrl("/authentication/login?failed")
oauth2Login() 开启OAuth 2.0或OpenID Connect 1.0身份验证 authorizeRequests()..anyRequest().authenticated()..and().oauth2Login()
rememberMe() 开启配置“记住我”的验证 authorizeRequests().antMatchers("/**").hasRole("USER").and().formLogin().permitAll().and().rememberMe()
addFilter() 添加自定义的filter addFilter(new CustomFilter())
addFilterAt() 在指定filter相同位置上添加自定义filter addFilterAt(new CustomFilter(), UsernamePasswordAuthenticationFilter.class)
addFilterAfter() 在指定filter位置后添加自定义filter addFilterAfter(new CustomFilter(), UsernamePasswordAuthenticationFilter.class)
requestMatchers() 开启配置HttpSecurity,仅当RequestMatcher相匹配时开启 requestMatchers().antMatchers("/api/**")
antMatchers() 其可以与authorizeRequests()、RequestMatcher匹配,如:requestMatchers().antMatchers("/api/**")
logout() 添加退出登录支持。当使用WebSecurityConfigurerAdapter时,这将自动应用。默认情况是,访问URL”/ logout”,使HTTP Session无效来清除用户,清除已配置的任何#rememberMe()身份验证,清除SecurityContextHolder,然后重定向到”/login?success” logout().deleteCookies("remove").invalidateHttpSession(false).logoutUrl("/custom-logout").logoutSuccessUrl("/logout-success");


HttpSecurity还有很多方法供我们使用,去配置HttpSecurity。由于太多这边就不一一说明,有兴趣可去研究。


3. WebSecurityConfigurerAdapter使用


WebSecurityConfigurerAdapter示例:


@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
 @Autowired
 private MyFilterSecurityInterceptor myFilterSecurityInterceptor;
 protected void configure(HttpSecurity http) throws Exception {    
     http
     //request 设置
     .authorizeRequests()   //http.authorizeRequests() 方法中的自定义匹配
     .antMatchers("/resources/**", "/signup", "/about").permitAll() // 指定所有用户进行访问指定的url          
     .antMatchers("/admin/**").hasRole("ADMIN")  //指定具有特定权限的用户才能访问特定目录,hasRole()方法指定用户权限,且不需前缀 “ROLE_“  
     .antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")//          
     .anyRequest().authenticated()  //任何请求没匹配的都需要进行验证                                           
     .and()        //login设置  自定义登录页面且允许所有用户登录
     .formLogin()      
     .loginPage("/login") //The updated configuration specifies the location of the log in page  指定自定义登录页面
     .permitAll(); // 允许所有用户访问登录页面. The formLogin().permitAll() 方法
     .and 
     .logout()  //logouts 设置                                                              
     .logoutUrl("/my/logout")  // 指定注销路径                                              
     .logoutSuccessUrl("/my/index") //指定成功注销后跳转到指定的页面                                        
     .logoutSuccessHandler(logoutSuccessHandler)  //指定成功注销后处理类 如果使用了logoutSuccessHandler()的话, logoutSuccessUrl()就会失效                                
     .invalidateHttpSession(true)  // httpSession是否有效时间,如果使用了 SecurityContextLogoutHandler,其将被覆盖                                        
     .addLogoutHandler(logoutHandler)  //在最后增加默认的注销处理类LogoutHandler                
     .deleteCookies(cookieNamesToClear);//指定注销成功后remove cookies
     //增加在FilterSecurityInterceptor前添加自定义的myFilterSecurityInterceptor
     http.addFilterBefore(myFilterSecurityInterceptor, FilterSecurityInterceptor.class);
   }
复制代码


NOTE:此示例只供参考


4. filter顺序


Spring Security filter顺序:


Filter Class 说明
ChannelProcessingFilter 访问协议控制过滤器,可能会将我们重新定向到另外一种协议,从http转换成https
SecurityContextPersistenceFilter 创建SecurityContext安全上下文信息和request结束时清空SecurityContextHolder
ConcurrentSessionFilter 并发访问控制过滤器,主要功能:SessionRegistry中获取SessionInformation来判断session是否过期,从而实现并发访问控制。
HeaderWriterFilter 给http response添加一些Header
CsrfFilter 跨域过滤器,跨站请求伪造保护Filter
LogoutFilter 处理退出登录的Filter
X509AuthenticationFilter 添加X509预授权处理机制支持
CasAuthenticationFilter 认证filter,经过这些过滤器后SecurityContextHolder中将包含一个完全组装好的Authentication对象,从而使后续鉴权能正常执行
UsernamePasswordAuthenticationFilter 认证的filter,经过这些过滤器后SecurityContextHolder中将包含一个完全组装好的Authentication对象,从而使后续鉴权能正常执行。表单认证是最常用的一个认证方式。
BasicAuthenticationFilter 认证filter,经过这些过滤器后SecurityContextHolder中将包含一个完全组装好的Authentication对象,从而使后续鉴权能正常执行
SecurityContextHolderAwareRequestFilter 此过滤器对ServletRequest进行了一次包装,使得request具有更加丰富的API
JaasApiIntegrationFilter (JAAS)认证方式filter
RememberMeAuthenticationFilter 记忆认证处理过滤器,即是如果前面认证过滤器没有对当前的请求进行处理,启用了RememberMe功能,会从cookie中解析出用户,并进行认证处理,之后在SecurityContextHolder中存入一个Authentication对象。
AnonymousAuthenticationFilter 匿名认证处理过滤器,当SecurityContextHolder中认证信息为空,则会创建一个匿名用户存入到SecurityContextHolder中
SessionManagementFilter 会话管理Filter,持久化用户登录信息,可以保存到session中,也可以保存到cookie或者redis中
ExceptionTranslationFilter 异常处理过滤器,主要拦截后续过滤器(FilterSecurityInterceptor)操作中抛出的异常。
FilterSecurityInterceptor 安全拦截过滤器类,获取当前请求url对应的ConfigAttribute,并调用accessDecisionManager进行访问授权决策。


spring security的默认filter链:


SecurityContextPersistenceFilter
->HeaderWriterFilter
->LogoutFilter
->UsernamePasswordAuthenticationFilter
->RequestCacheAwareFilter
->SecurityContextHolderAwareRequestFilter
->SessionManagementFilter
->ExceptionTranslationFilter
->FilterSecurityInterceptor
复制代码


在上节我们已分析了核心的filter源码以及功能。可回看上节源码分析更加深入的了解各个filter工作原理。


总结:


在认证和访问授权过程前,首先必须进行WebSecurityConfigurer符合自身应用的security Configurer,也要清楚filter链的先后顺序,才能更好理解spring security的工作原理以及在项目中出现的问题定位。了解完准备工作,接下来将展开对认证和访问授权模块的工作流程研究以及项目示例分析。最后如有错误可评论告知。


各位看官还可以吗?喜欢的话,动动手指点个💗,点个关注呗!!谢谢支持!



目录
相关文章
|
5月前
|
负载均衡 监控 Java
Spring Cloud Gateway 全解析:路由配置、断言规则与过滤器实战指南
本文详细介绍了 Spring Cloud Gateway 的核心功能与实践配置。首先讲解了网关模块的创建流程,包括依赖引入(gateway、nacos 服务发现、负载均衡)、端口与服务发现配置,以及路由规则的设置(需注意路径前缀重复与优先级 order)。接着深入解析路由断言,涵盖 After、Before、Path 等 12 种内置断言的参数、作用及配置示例,并说明了自定义断言的实现方法。随后重点阐述过滤器机制,区分路由过滤器(如 AddRequestHeader、RewritePath、RequestRateLimiter 等)与全局过滤器的作用范围与配置方式,提
Spring Cloud Gateway 全解析:路由配置、断言规则与过滤器实战指南
|
5月前
|
Java 关系型数据库 MySQL
Spring Boot自动配置:魔法背后的秘密
Spring Boot 自动配置揭秘:只需简单配置即可启动项目,背后依赖“约定大于配置”与条件化装配。核心在于 `@EnableAutoConfiguration` 注解与 `@Conditional` 系列条件判断,通过 `spring.factories` 或 `AutoConfiguration.imports` 加载配置类,实现按需自动装配 Bean。
|
5月前
|
人工智能 Java 开发者
【Spring】原理解析:Spring Boot 自动配置
Spring Boot通过“约定优于配置”的设计理念,自动检测项目依赖并根据这些依赖自动装配相应的Bean,从而解放开发者从繁琐的配置工作中解脱出来,专注于业务逻辑实现。
1881 0
|
7月前
|
Java Spring
Spring Boot配置的优先级?
在Spring Boot项目中,配置可通过配置文件和外部配置实现。支持的配置文件包括application.properties、application.yml和application.yaml,优先级依次降低。外部配置常用方式有Java系统属性(如-Dserver.port=9001)和命令行参数(如--server.port=10010),其中命令行参数优先级高于系统属性。整体优先级顺序为:命令行参数 &gt; Java系统属性 &gt; application.properties &gt; application.yml &gt; application.yaml。
1142 0
|
4月前
|
前端开发 Java 应用服务中间件
《深入理解Spring》 Spring Boot——约定优于配置的革命者
Spring Boot基于“约定优于配置”理念,通过自动配置、起步依赖、嵌入式容器和Actuator四大特性,简化Spring应用的开发与部署,提升效率,降低门槛,成为现代Java开发的事实标准。
|
4月前
|
缓存 安全 Java
《深入理解Spring》过滤器(Filter)——Web请求的第一道防线
Servlet过滤器是Java Web核心组件,可在请求进入容器时进行预处理与响应后处理,适用于日志、认证、安全、跨域等全局性功能,具有比Spring拦截器更早的执行时机和更广的覆盖范围。
|
5月前
|
缓存 Java 应用服务中间件
Spring Boot配置优化:Tomcat+数据库+缓存+日志,全场景教程
本文详解Spring Boot十大核心配置优化技巧,涵盖Tomcat连接池、数据库连接池、Jackson时区、日志管理、缓存策略、异步线程池等关键配置,结合代码示例与通俗解释,助你轻松掌握高并发场景下的性能调优方法,适用于实际项目落地。
858 5
|
5月前
|
传感器 Java 数据库
探索Spring Boot的@Conditional注解的上下文配置
Spring Boot 的 `@Conditional` 注解可根据不同条件动态控制 Bean 的加载,提升应用的灵活性与可配置性。本文深入解析其用法与优势,并结合实例展示如何通过自定义条件类实现环境适配的智能配置。
291 0
探索Spring Boot的@Conditional注解的上下文配置
|
6月前
|
安全 算法 Java
在Spring Boot中应用Jasypt以加密配置信息。
通过以上步骤,可以在Spring Boot应用中有效地利用Jasypt对配置信息进行加密,这样即使配置文件被泄露,其中的敏感信息也不会直接暴露给攻击者。这是一种在不牺牲操作复杂度的情况下提升应用安全性的简便方法。
1228 10
|
7月前
|
人工智能 安全 Java
Spring Boot yml 配置敏感信息加密
本文介绍了如何在 Spring Boot 项目中使用 Jasypt 实现配置文件加密,包含添加依赖、配置密钥、生成加密值、在配置中使用加密值及验证步骤,并提供了注意事项,确保敏感信息的安全管理。
1378 1

热门文章

最新文章