怎么自建导购网站做淘客滨州网站建设
- 作者: 五速梦信息网
- 时间: 2026年03月21日 06:46
当前位置: 首页 > news >正文
怎么自建导购网站做淘客,滨州网站建设,做led开关电源上什么网站好,学剪辑有必要报班吗theme: smartblue highlight: a11y-dark
一、前言及准备
1.1 SpringSecurity过滤器链简单介绍
在Spring Security中#xff0c;过滤器链#xff08;Filter Chain#xff09;是由多个过滤器#xff08;Filter#xff09;组成的#xff0c;这些过滤器按照一定的顺序对进…
theme: smartblue highlight: a11y-dark
一、前言及准备
1.1 SpringSecurity过滤器链简单介绍
在Spring Security中过滤器链Filter Chain是由多个过滤器Filter组成的这些过滤器按照一定的顺序对进入应用的请求进行处理。每个过滤器可以执行不同的安全操作如身份验证、授权、安全上下文的建立等。
过滤器是一种典型的AOP思想我们将通过源码分析这些过滤器如何被加载以及组成过滤器链。
1.2 SpringSecurity配置类
该类主要对SpringSecurity进行一系列配置后续过滤器链的初始化和加载也是基于这个配置类。当前配置类仅供参考。注意里面两个很重要的方法 #configure(WebSecurity web)以及#configure(WebSecurity web)他们对过滤器链的初始化很重要。
Configurationpublic class SecurityConfig extends WebSecurityConfigurerAdapter {// 自定义登录成功或失败处理器,退出登录处理器Autowiredprivate MyAuthenticationService myAuthenticationService;// 自定义验证码过滤器Autowiredprivate ValidateCodeFilter validateCodeFilter;// 自定义权限不足处理Autowiredprivate MyAccessDeniedHandler myAccessDeniedHandler;// 权限相关ServiceAutowiredprivate PermissionService permissionService;Overridepublic void configure(WebSecurity web) throws Exception {//解决静态资源被拦截的问题web.ignoring().antMatchers(/css/, /images/, /js/, /code/);}/*** http请求方法** param http* throws Exception*/Overrideprotected void configure(HttpSecurity http) throws Exception {// 加入用户名密码验证过滤器的前面http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class);// 查询数据库所有权限列表ListPermission list permissionService.list();for (Permission permission : list) {// 添加请求权限http.authorizeRequests().antMatchers(permission.getPermissionUrl()).hasAuthority(permission.getPermissionTag());}// 设置权限不足的信息http.exceptionHandling().accessDeniedHandler(myAccessDeniedHandler);http.formLogin()// 开启表单认证.loginPage(/toLoginPage)// 自定义登录页面.loginProcessingUrl(/login)//表单提交的路径.usernameParameter(username).passwordParameter(password)//自定义input的name值.successForwardUrl(/)//登录成功之后跳转的路径.successHandler(myAuthenticationService).failureHandler(myAuthenticationService)//登录成功或者失败的处理.and().logout().logoutUrl(/logout).logoutSuccessHandler(myAuthenticationService).and().rememberMe()//开启记住我功能.tokenValiditySeconds(1209600)//token失效时间 默认是2周.rememberMeParameter(remember-me)//自定义表单input值.tokenRepository(getPersistentTokenRepository()).and().authorizeRequests().antMatchers(/toLoginPage).permitAll()//放行登录页面.anyRequest().authenticated();//关闭csrf防护http.csrf().disable();//加载同源域名下iframe页面http.headers().frameOptions().sameOrigin();// 开启跨域支持http.cors().configurationSource(corsConfigurationSource());}} 1.3 过滤器链加载方法入口
Spring boot启动中会加载spring.factories文件, 在文件中有对应针对Spring Security的过滤器链 的配置信息所以spring.factories来找过滤器链加载方法入口 所以我们的过滤器链加载方法入口位于org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration#springSecurityFilterChain()
二、 源码导读
SpringSecurity的过滤器链创建本质就是读取SecurityConfig配置类并且通过核心配置方法#configure(WebSecurity web)以及#configure(WebSecurity web)生成一个个配置对象最终每个配置对象会转换成一个过滤器对象这些过滤器对象组成过滤器链。
前面已经提到了配置类中的 #configure(WebSecurity web)以及#configure(WebSecurity web)非常重要。他们将分别加载到一个HttpSecurity对象和一个名为ignoredRequests的ArrayList之中 并且过滤器链也是由这两部分转换后组成。
2.1 SpringSecurity配置信息的加载
由前面的内容我们已经定位到过滤器链加载的方法入口位于 org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration#springSecurityFilterChain()
Bean(name AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
public Filter springSecurityFilterChain() throws Exception {boolean hasConfigurers webSecurityConfigurers ! null !webSecurityConfigurers.isEmpty();if (!hasConfigurers) {WebSecurityConfigurerAdapter adapter objectObjectPostProcessor.postProcess(new WebSecurityConfigurerAdapter() {});webSecurity.apply(adapter);}// 加载方法return webSecurity.build();
}我们从该方法的webSecurity.build()按照下图一路点击最终会进入到org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder#doBuild() 方法该方法是加载配置和过滤器链的主要方法。 org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder#doBuild()如下
Override
protected final O doBuild() throws Exception {synchronized (configurers) {buildState BuildState.INITIALIZING;beforeInit();// 【1】.初始化主要构建HttpSecurity对象以及内部的配置对象init();buildState BuildState.CONFIGURING;beforeConfigure();// 【2】ignoredRequests集合的构建configure();buildState BuildState.BUILDING;// 【3】组装过滤器链O result performBuild();buildState BuildState.BUILT;return result;}可以看到当前的configurers加载的就是我们自定义的配置类 2.1.1 构建带有配置信息的HttpSecurity对象
我们从上述的doBuild()方法体中点击init()方法进入其内部
org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder#init()
private void init() throws Exception {CollectionSecurityConfigurerO, B configurers getConfigurers();for (SecurityConfigurerO, B configurer : configurers) {// 构建HttpSecurity对象configurer.init((B) this);}for (SecurityConfigurerO, B configurer : configurersAddedInInitializing) {configurer.init((B) this);}
}接着点击构建HttpSecurity的对象的方法configurer.init()方法
org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter#init()发现真正构建HttpSecurity的方法其实是 getHttp()
public void init(final WebSecurity web) throws Exception {// 真正构建HttpSecurity的方法final HttpSecurity http getHttp();// 将HttpSecurity对象作为SecurityFilterChainBuilder对象返回web.addSecurityFilterChainBuilder(http).postBuildAction(() - {FilterSecurityInterceptor securityInterceptor http.getSharedObject(FilterSecurityInterceptor.class);web.securityInterceptor(securityInterceptor);});
}点击进入 getHttp()
protected final HttpSecurity getHttp() throws Exception {/省略其他/// 【1】.新建一个HttpSecurity对象http new HttpSecurity(objectPostProcessor, authenticationBuilder,sharedObjects);if (!disableDefaults) {// 【2】.设置HttpSecurity对象中configurers配置对象以及filter过滤器对象http.csrf().and() .addFilter(new WebAsyncManagerIntegrationFilter()) .exceptionHandling().and().headers().and().sessionManagement().and().securityContext().and().requestCache().and().anonymous().and().servletApi().and().apply(new DefaultLoginPageConfigurer()).and().logout();/省略/}// 【3】.执行SecurityConfig中的configure(HttpSecurity http)方法configure(http);return http;
}观察上述代码我们发现首先通过new HttpSecurity()新建了一个HttpSecurity对象并且在下方设置HttpSecurity对象中configurers属性以及filter属性。
当执行完下面代码时即【2】处的代码 http.csrf().and() //【添加CsrfConfigurer】.addFilter(new WebAsyncManagerIntegrationFilter()) // 【添加 WebAsyncManagerIntegrationFilter】.exceptionHandling().and() // 【添加 ExceptionHandlingConfigurer】.headers().and() // 【添加 HeadersConfigurer】.sessionManagement().and()// 【添加SessionManagementConfigurer】.securityContext().and()// 【添加SecurityContextConfigurer】.requestCache().and()// 【添加RequestCacheConfigurer】.anonymous().and()// 【添加AnonymousConfigurer】.servletApi().and()// 【添加ServletApiConfigurer】.apply(new DefaultLoginPageConfigurer()).and()//【添加DefaultLoginPageConfigurer】.logout(); // 【添加LogoutConfigure】rHttpSecurity对象中configurers属性以及filter如下此时size分别为 10 和 1 执行了【2】的代码后会执行【3】的代码 configure(http); 该方法会调用SecurityConfig配置类文件的configure()方法由于此时传入的HttpSecurity对象所以调用的 SecurityConfig配置类文件中的configure(HttpSecurity http)代码如下注意该部分为自定义的配置文件中方法需要伙伴自己去编写根据自己需求进行配置。当前仅供参考
Override
protected void configure(HttpSecurity http) throws Exception {// 加入用户名密码验证过滤器的前 【添加ValidateCodeFilter】http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class);// 查询数据库所有权限列表ListPermission list permissionService.list();【添加ExpressionUrlAuthorizationConfigurer】for (Permission permission : list) {// 添加请求权限http.authorizeRequests().antMatchers(permission.getPermissionUrl()).hasAuthority(permission.getPermissionTag());}// 设置权限不足的信息 http.exceptionHandling().accessDeniedHandler(myAccessDeniedHandler);http.formLogin()// 开启表单认证 【添加FormLoginConfigurer】.loginPage(/toLoginPage)// 自定义登录页面.loginProcessingUrl(/login)//表单提交的路径.usernameParameter(username).passwordParameter(password)//自定义input的name值.successForwardUrl(/)//登录成功之后跳转的路径.successHandler(myAuthenticationService).failureHandler(myAuthenticationService)//登录成功或者失败的处理.and().logout().logoutUrl(/logout).logoutSuccessHandler(myAuthenticationService).and().rememberMe()//开启记住我功能 【添加 RememberMeConfigurer】.tokenValiditySeconds(1209600)//token失效时间 默认是2周.rememberMeParameter(remember-me)//自定义表单input值.tokenRepository(getPersistentTokenRepository()).and().authorizeRequests().antMatchers(/toLoginPage).permitAll()//放行登录页面.anyRequest().authenticated();//关闭csrf防护// 【移除CsrfConfigurer】http.csrf().disable();//加载同源域名下iframe页面http.headers().frameOptions().sameOrigin();// 开启跨域支持// 【添加CorsConfigurer】http.cors().configurationSource(corsConfigurationSource());}执行完该方法后configurers属性以及filter属性如下size变为13和2 HttpSecurity对象构建完成之后configurers中每个Configurer对象最终都会转换为Filter对象
2.1.2 列表集合 ignoredRequests 的创建
当执行完init()后HttpSecurity对象构建完成并且存放在一个叫做securityFilterChainBuilders的集合对象中。 此时我们回到org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder#doBuild()在执行init()方法之后会有一个configure()方法点击进去可以看到
private void configure() throws Exception {CollectionSecurityConfigurerO, B configurers getConfigurers();for (SecurityConfigurerO, B configurer : configurers) {// 【加载配置类SecurityConfig中的configure(WebSecurity web)方法】configurer.configure((B) this);}
}注意看
configurer.configure((B) this);
这句代码此时的this是一个WebSecurity对象
仔细想想在配置类文件中不正是有一个#configure(WebSecurity web)配置方法吗没错这句代码正是执行了配置文件中的该方法。
#configure(WebSecurity web)方法体 执行完这一行代码之后ignoredRequests变量已经被赋值而且变量中的值是和上面配置方法中配置对应的。 OK此时SpringSecurity配置信息的加载就已经完成接下来就是将这些配置信息转换成过滤器并组成过滤器链
2.2 过滤器链的加载
加载完配置文件后我们的配置信息分别被存放在两部分ignoredRequests和securityFilterBulders之中下面再来看看这两部分是如何构建成过滤器链的。
2.2.1 ignoredRequests 转换成过滤器链 此时我们再次回到此时我们回到org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder#doBuild() 找到构造过滤器链的方法performBuild()
org.springframework.security.config.annotation.web.builders.WebSecurity#performBuild()
Override
protected Filter performBuild() throws Exception {/忽略部分代码/【1】计算过滤器链长度int chainSize ignoredRequests.size() securityFilterChainBuilders.size();ListSecurityFilterChain securityFilterChains new ArrayList(chainSize);【2】将ignoredRequests集合中的对象转为过滤器加入到过滤器链中for (RequestMatcher ignoredRequest : ignoredRequests) {securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));}【3】将securityFilterChainBuilder转为过滤器加入到过滤器链中for (SecurityBuilder? extends SecurityFilterChain securityFilterChainBuilder : securityFilterChainBuilders) {securityFilterChains.add(securityFilterChainBuilder.build());}/忽略部分代码/}/忽略部分代码/return result;
}
【1】处代码计算过滤器链长度chainSizeDebug中计算结果如下 【2】处代码将ignoredRequests集合中的对象转为过滤器加入到过滤器链securityFilterChains 中执行结果如下 ignoredRequests转换成过滤器链完成
【3】处的代码就是 securityFilterBulders的的处理。下面接着讲。
2.2.2 securityFilterBulders 转换成过滤器链
在上面的org.springframework.security.config.annotation.web.builders.WebSecurity#performBuild() 方法中通过观察看到处理securityFilterBulders代码就一句话
securityFilterChains.add(securityFilterChainBuilder.build());我们从securityFilterChainBuilder.build(),按照下面顺序一路点击 我们将会定位到 org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder#configure()
private void configure() throws Exception {【1】获取配置对象CollectionSecurityConfigurerO, B configurers getConfigurers();for (SecurityConfigurerO, B configurer : configurers) {【2】将配置对象加入到过滤器链configurer.configure((B) this);}
}在【1】处我们将得到从securityFilterChainBuilder中得到configurers配置列表 在【2】处会循环配置列表对每个配置对象处理并且最终加入到过滤器链中。 比如当前是ExceptionHandlingConfigurer 那么就会执行 org.springframework.security.config.annotation.web.configurers.ExceptionHandlingConfigurer#configure()
Override
public void configure(H http) {AuthenticationEntryPoint entryPoint getAuthenticationEntryPoint(http);// 【1】创建 ExceptionTranslationFilterExceptionTranslationFilter exceptionTranslationFilter new ExceptionTranslationFilter(entryPoint, getRequestCache(http));AccessDeniedHandler deniedHandler getAccessDeniedHandler(http);exceptionTranslationFilter.setAccessDeniedHandler(deniedHandler);exceptionTranslationFilter postProcess(exceptionTranslationFilter);//【2】 ExceptionTranslationFilter加入到过滤器链http.addFilter(exceptionTranslationFilter);
}再比如当前是HeaderConfigurer,那么会执行org.springframework.security.config.annotation.web.configurers.HeadersConfigurer#configure()
Override
public void configure(H http) {【1】创建 HeaderWriterFilterHeaderWriterFilter headersFilter createHeaderWriterFilter();【2】加入到过滤器链http.addFilter(headersFilter);
}也就是说具体是什么类型的Filter是根据当前Configurer而决定的。
当我们执行完所有的configure()方法再次回到org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder#doBuild()
可以看到filter已经被加载出来 但是过滤器是有一定顺序的此时加载出来的过滤器并没有处理顺序。 当方法执行到 performBuild()内部时会进行排序 org.springframework.security.config.annotation.web.builders.HttpSecurity#performBuild()
Override
protected DefaultSecurityFilterChain performBuild() {【对过滤器进行排序】filters.sort(comparator);return new DefaultSecurityFilterChain(requestMatcher, filters);
}排序后的过滤器链 到这里拦截器链加载结束
- 上一篇: 怎么自己做微网站公司做网络推广哪个网站好
- 下一篇: 怎么自助建站百度新闻首页
相关文章
-
怎么自己做微网站公司做网络推广哪个网站好
怎么自己做微网站公司做网络推广哪个网站好
- 技术栈
- 2026年03月21日
-
怎么自己做网站的优化wordpress自动同步插件
怎么自己做网站的优化wordpress自动同步插件
- 技术栈
- 2026年03月21日
-
怎么自己做电影网站wordpress文章id排序
怎么自己做电影网站wordpress文章id排序
- 技术栈
- 2026年03月21日
-
怎么自助建站百度新闻首页
怎么自助建站百度新闻首页
- 技术栈
- 2026年03月21日
-
怎么做app网站网站建设都有哪些书
怎么做app网站网站建设都有哪些书
- 技术栈
- 2026年03月21日
-
怎么做qq分享网站wordpress数据库文件导入
怎么做qq分享网站wordpress数据库文件导入
- 技术栈
- 2026年03月21日
