You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何整合Spring Security+Thymeleaf+HTMX避免403错误?

问题描述

我是Spring Security的新手,尤其不熟悉它与Thymeleaf、HTMX的整合。我希望保留Spring Security的功能同时使用HTMX,但目前遇到了403错误。若在配置中禁用CSRF,应用会丢失所有认证视图,表现得像未集成Spring Security一样。

相关代码

index.html

<!DOCTYPE html>
<html lang="en" xmlns:th="https://thymeleaf.org">
   <head>
      <meta charset = "ISO-8859-1" />
      <link href = "css/styles.css" rel = "stylesheet" />
      <title>Logowanie</title>
      <script th:src="@{/js/scripts.js}" defer></script>
      <script src="https://unpkg.com/htmx.org@1.7.0" integrity="sha384-EzBXYPt0/T6gxNp0nuPtLkmRpmDBbjg6WmCUZRLXBBwYYmwAUxzlSGej0ARHX0Bo" crossorigin="anonymous"></script>
      <meta name="_csrf" content="${_csrf.token}"/>
      <meta name="_csrf_header" content="${_csrf.headerName}"/>
   </head>
   <body hx-boost="true">
    <div class="center">
      <h4>Witamy w panelu klienta!</h4>
      <button id="myButton" th:onclick="hello()">Hello Button</button>
      <button id="button2" th:onClick="info()">info in console</button>
      <p id="sayHello" hx-post="/hello" hx-swap="outerHTML">ppp</p>
      <!-- <div sec:authorize="hasRole('USER')">Text visible to user.</div>
      <div sec:authorize="hasRole('ADMIN')">Text visible to admin.</div>
      <div sec:authorize="isAuthenticated()">
         Text visible only to authenticated users.
      </div>
      Authenticated username:
      <div sec:authentication="name"></div>
      Authenticated user roles:
      <div sec:authentication="principal.authorities"></div> -->
    </div>
   </body>
</html>

Controller

@Controller
public class MainView {

    @GetMapping("/")
    public String mainView(Model model) {
        model.addAttribute("password", "dupka");
        return "index";
    }

    @GetMapping("/panel")
    public String panelView(Model model) {
        model.addAttribute("password", "dupeczka");
        return "test";
    }

    @PostMapping("/hello")
    // @PostMapping(headers = "HX-Request")
    public String furtherInfo() {
        return "fragments/invoices";
        // return "test";
    }
}

原配置文件

@Configuration
@EnableWebSecurity
public class MyGlobalSecurityConfig 
{
    
    @Autowired
    protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth
        .inMemoryAuthentication()
        .withUser("user")
        .password("{noop}password")
        .roles("USER")
        .and()
        .withUser("admin")
        .password("{noop}password")
        .roles("ADMIN");
    }
}

尝试禁用CSRF的修改

@Bean
     public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
         http
         .csrf().disable();
         return http.build();
     }
解决方案

1. 修复Spring Security配置,保留CSRF并配置完整认证规则

禁用CSRF后丢失认证视图的核心原因是:你只配置了csrf().disable(),没有添加任何授权规则,Spring Security默认会允许所有请求匿名访问,因此不会触发登录页面,看起来像未集成Security。

修改配置文件,添加完整的SecurityFilterChain,包含授权规则、登录/登出配置:

@Configuration
@EnableWebSecurity
public class MyGlobalSecurityConfig {

    @Autowired
    protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .inMemoryAuthentication()
                .withUser("user")
                .password("{noop}password")
                .roles("USER")
                .and()
                .withUser("admin")
                .password("{noop}password")
                .roles("ADMIN");
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                // 配置授权规则
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers("/", "/js/**", "/css/**").permitAll() // 允许首页和静态资源匿名访问
                        .anyRequest().authenticated() // 其他所有请求需要认证
                )
                // 启用默认登录页面,允许匿名访问登录页
                .formLogin(form -> form
                        .permitAll()
                )
                // 配置登出,允许匿名访问登出接口
                .logout(logout -> logout
                        .permitAll()
                )
                // 保留CSRF保护,不需要禁用
                .csrf(csrf -> csrf
                        // 可选:如果某些HTMX请求不需要CSRF(不推荐),可以忽略
                        // .ignoringRequestMatchers("/hello")
                );
        return http.build();
    }
}

2. 让HTMX自动携带CSRF令牌

你已经在index.html中添加了CSRF的meta标签,但HTMX不会自动读取并携带这些令牌,需要添加一段脚本让HTMX在每个请求中带上CSRF头:

在index.html的<head>或<body>末尾添加:

<script>
document.addEventListener('htmx:configRequest', function(evt) {
    const csrfToken = document.querySelector('meta[name="_csrf"]').content;
    const csrfHeader = document.querySelector('meta[name="_csrf_header"]').content;
    evt.headers[csrfHeader] = csrfToken;
});
</script>

3. 验证Thymeleaf的Spring Security集成(可选)

如果你要启用页面中的sec:标签,需要确保引入了Thymeleaf的Spring Security依赖,并在HTML中添加命名空间:

<html lang="en" xmlns:th="https://thymeleaf.org" xmlns:sec="https://www.thymeleaf.org/extras/spring-security">

这样配置后,HTMX的POST请求会正确携带CSRF令牌,不会触发403错误,同时Spring Security的认证功能(登录页、权限控制)也能正常工作。


内容的提问来源于stack exchange,提问作者Karol Wilczyński

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 05:37:03