Spring Boot如何获取CSRF token 解决请求中CSRF token为null问题
问题:请求中获取到的CSRF Token为null
问题相关代码
- 读取CSRF Token的实现代码
Object obj=request.getSession().getAttribute(WebSessionServerCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN"));
- 项目中CSRF Token生成配置代码
@Bean public SecurityWebFilterChain securitygWebFilterChain(ServerHttpSecurity http) { http.csrf() .csrfTokenRepository(new WebSessionServerCsrfTokenRepository()) .requireCsrfProtectionMatcher(getURLsForDisabledCSRF()).and() .authorizeExchange() .pathMatchers(ALLOWED_PATHS).permitAll() .pathMatchers(ALLOWED_METHODS).permitAll() .anyExchange() .authenticated().and() .securityContextRepository(NoOpServerSecurityContextRepository.getInstance()).formLogin().disable() .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint()) .and().csrf(csrf -> csrf.csrfTokenRepository(CookieServerCsrfTokenRepository.withHttpOnlyFalse())); return http.build(); }
根因分析
- CSRF配置重复,后定义的规则覆盖了前面的规则
同一段配置里先后定义了两套CSRF Token存储方案:第一套是基于WebSession存储的WebSessionServerCsrfTokenRepository,第二套是基于Cookie存储的CookieServerCsrfTokenRepository。Spring Security配置生效逻辑是同类型配置后定义的会覆盖先定义的,最终生效的是Cookie存储方案,根本不会往WebSession里写入CSRF_TOKEN属性,此时从Session读取必然返回null。 - CSRF Token默认懒加载,未触发生成逻辑时读取不到值
Spring Security的CSRF Token默认不会在请求进入时就生成,只有当请求命中CSRF校验逻辑、或者代码主动触发Token生成时,才会把Token写入对应的存储介质,在这之前读取存储介质拿到的就是null。 - 无状态SecurityContext配置和Session存储Token逻辑冲突
配置了NoOpServerSecurityContextRepository.getInstance()代表SecurityContext完全不存储在Session中,整套鉴权逻辑走无状态模式,这种场景下WebSession的属性持久化本身就可能受影响,进一步导致Session存Token失败。
解决步骤
- 统一CSRF存储配置,删除重复定义
二选一保留一种存储方案即可:如果要走Session存储Token,直接删除最后一行配置CookieServerCsrfTokenRepository的代码;如果要走Cookie存储Token,就删掉从Session读Token的逻辑,改为从请求Cookie中读取默认名为XSRF-TOKEN的字段值。 - 主动触发Token生成,解决懒加载问题
如果保留Session存储方案,新增一个全局WebFilter,在请求进入业务逻辑前主动触发Token生成和持久化,参考代码:@Bean public WebFilter csrfTokenPersistFilter(ServerCsrfTokenRepository csrfTokenRepository) { return (exchange, chain) -> { CsrfToken token = csrfTokenRepository.loadToken(exchange).block(); if (token == null) { token = csrfTokenRepository.generateToken(exchange); csrfTokenRepository.saveToken(exchange, token).block(); } exchange.getAttributes().put(CsrfToken.class.getName(), token); return chain.filter(exchange); }; } - 校验Session可用性
确认项目没有配置SessionCreationPolicy.STATELESS这类禁用Session的策略,WebFlux项目需要引入对应的Session依赖(比如spring-session-core、对应存储的spring-session组件),保证WebSession能正常持久化属性。 - 校验CSRF白名单范围
确认读取Token的接口不在getURLsForDisabledCSRF()定义的CSRF白名单路径内,白名单路径会跳过整套CSRF逻辑,不会生成对应Token。
内容的提问来源于stack exchange,提问作者Mohd adil
相关产品推荐
相关产品推荐

