Spring 引导,Spring 安全和 Thymeleaf:将 CsrfFilter 应用于具有表单的网站

Spring Boot, Spring Security and Thymeleaf: Apply CsrfFilter to website with form

我正在使用 Thymeleaf 的 Spring 安全性,并希望在不同的站点上创建一个登录和注册表单,同时使用 CSRF 保护。保护登录站点很容易,就像下面的 WebSecurity 配置一样

@Override
protected void configure(final HttpSecurity http) throws Exception {
    http
            .formLogin()
            .loginPage("/login")
            .permitAll()
            .and()
            .requestMatchers()
            .antMatchers("/login", "/oauth/authorize", "/oauth/confirm_access")
            .and()
            .authorizeRequests()
            .anyRequest()
            .authenticated();
}

Spring 支持通过在配置方法中构建的安全过滤器链添加 CSRF 保护。此过滤器链包含一个 adds/evaluates CSRF 令牌的 CSRFFilter。然后,此过滤器链用于上述配置中定义的所有匹配项。可以在方法

中找到获取应用于请求的过滤器的机制 here

doFilterInternal(ServletRequest, ServletResponse, FilterChain)

问题是,如果我将“/register”站点添加到此配置中,用户将首先被重定向到“/login”站点。如果我不将它添加到上面的配置中,则不会应用提到的 FilterChain(因此不会应用 CsrfFilter)。

所以我想在“/register”站点的过滤器链中重用CsrfFilter,但我不知道该怎么做。

我更喜欢这种方法而不是其他想法,例如按照建议编写自定义 CSRF 过滤器 here or here

从所有这些我了解到问题是您希望人们无需先登录即可访问/注册。这是一个简单的修复:

@Override
protected void configure(final HttpSecurity http) throws Exception {
    http
            .formLogin()
            .loginPage("/login")
            .permitAll()
            .and()
            .requestMatchers()
// add this line
.antMatchers("/register").permitAll().and

//
            .antMatchers("/login", "/oauth/authorize", "/oauth/confirm_access")
            .and()
            .authorizeRequests()
            .anyRequest()
            .authenticated();
}

事实证明,Spring 安全过滤器链应用于提供给 requestMatchers().antMatchers() 的列表中提到的所有端点。

所以要对不是登录站点的站点使用 CSRF 保护,我只需将它添加到此列表,然后允许所有访问它,这样就不会重定向到登录页面。我的最终配置如下所示

@Override
protected void configure(final HttpSecurity http) throws Exception {
    http.requestMatchers()
            // consider these patterns for this config and the Security Filter Chain
            .antMatchers("/login", "/register", "/oauth/authorize", "/oauth/confirm_access", "/oauth/token_key",
                    "/oauth/check_token", "/oauth/error")
            .and()
            // define authorization behaviour
            .authorizeRequests()
            // /register is allowed by anyone
            .antMatchers("/register").permitAll()
            // /oauth/authorize needs authentication; enables redirect to /login
            .antMatchers("/oauth/authorize").authenticated()
            // any other request in the patterns above are forbidden
            .anyRequest().denyAll()
            .and()
            .formLogin()
            // we have a custom login page at /login
            // that is permitted to everyone
            .loginPage("/login").permitAll();
}