@Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
http
.csrf(csrf -> csrf.csrfTokenRepository(cookieServerCsrfTokenRepository.withHttponlyFalse()))
return http.build();
}
以上通过cookie持久化XSRF-TOKEN值,jS读取cookie中的值发起请求时需携带X-XSRF-TOKEN
请求头,默认情况GET,HEAD,TRACE,OPTIONS请求方式是放行的,具体实现在DefaultRequireCsrfProtectionMatcher
类。如果需要特殊定制,可以自定义实现类实现ServerWebExchangeMatcher,并替换默认DefaultRequireCsrfProtectionMatcher:
@Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
http
.csrf(csrf -> csrf.csrfTokenRepository(cookieServerCsrfTokenRepository.withHttponlyFalse())
.requireCsrfProtectionMatcher(new CustomServerWebExchangeMatcher());
return http.build();
}
cookieServerCsrfTokenRepository does not add cookie
在我们按照上述配置分别测试GET请求和POST请求时,发现GET请求响应cookie中并没有XSRF-TOKEN,原因在响应式编程中CsrfToken
并没有被订阅。具体问题解析在Spring Security issues中找到答案;
最后也提供了解决方式:
@Slf4j
@Component
public class CsrfHelperFilter implements WebFilter {
@Override
public Mono filter(ServerWebExchange exchange, WebFilterChain chain) {
String key = CsrfToken.class.getName();
Mono csrfToken = null != exchange.getAttribute(key) ? exchange.getAttribute(key) : Mono.empty();
return csrfToken.doonSuccess(token -> {
Responsecookie cookie = Responsecookie.from("XSRF-TOKEN", token.getToken()).maxAge(Duration.ofHours(1))
.httponly(false).path("/").build();
log.debug("cookie: {}", cookie);
exchange.getResponse().getcookies().add("XSRF-TOKEN", cookie);
}).then(chain.filter(exchange));
}
}



