会话令牌不会被接受

前端开发 2026-07-08

所以我现在在自学,正在做一个全栈项目。我用Spring Boot构建了后端,并且使用基于会话的认证。CORS配置已经覆盖了我尝试过的所有可能的允许来源,但我仍然有一个问题:

后端在我的树莓派上以Docker镜像运行,地址是192.168.x.x:8081,这在用Postman进行测试时工作正常。

当在VS Code的 Live Server或 Live Preview中使用时,我的登录/注册可以正常工作,登录成功后我被重定向到仪表板,在那里应该执行一个GET请求,但每次都会返回401状态码。

在DevTools的 SessionID旁边有一个“!”、并带有一段较长的描述,指出cookie是跨站点来源且不会被接受。

我的问题是:
有没有办法让它工作起来?
因为我在想,是否也可以把一切都在我的笔记本电脑上用Docker运行,但Docker仍然有不同的“网络”,所以仍然存在跨站点问题。

希望我把事情说清楚了,因为我确实有点糊涂。

如果有帮助,这里是我的Security配置:

package de.ExpenseTracker.security;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.annotation.web.configurers.LogoutConfigurer;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
public class SecurityConfig {
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .cors(Customizer.withDefaults())
                .csrf(AbstractHttpConfigurer::disable)
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                        .requestMatchers("/users/**").permitAll()
                        .anyRequest().authenticated()
                )
                .formLogin(form -> form
                        .loginProcessingUrl("/users/login")
                        .successHandler((req, res, auth) -> res.setStatus(200))
                        .failureHandler((req, res, ex) -> res.sendError(401))
                )
                .exceptionHandling(e -> e
                        .authenticationEntryPoint((req, res, ex) -> res.sendError(401))
                )
                .logout(LogoutConfigurer::permitAll);

        return http.build();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

以及CORS配置:

package de.ExpenseTracker.security;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.util.List;

@Configuration
public class CorsConfig {

    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration config = new CorsConfiguration();

        config.setAllowedOrigins(List.of(
                "http://127.0.0.1:3000",
                "http://localhost:3000",
                "http://192.168.178.44:3000",
                "http://127.0.0.1:5500",
                "http://192.168.178.31:5500"
        ));

        config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"));
        config.setAllowedHeaders(List.of("*"));
        config.setAllowCredentials(true);

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);

        return source;
    }
}

以及我的 dev.properties 文件:

spring.datasource.url=jdbc:postgresql://192.168.x.x:5432/expensetracker_test
spring.datasource.username=e
spring.datasource.password=@
spring.jpa.hibernate.ddl-auto=update
server.servlet.session.cookie.same-site=Lax

解决方案

One thing that stands out is that your backend is issuing a new session ID on every request:

Received token: null
Generated session token: xxx

Received token: xxx
Generated session token: yyy

This suggests the server is not finding the existing session and is creating a new one each time.

Before focusing on Docker networking, CORS, or Spring Security, check the actual Cookie request header in the browser's Network tab:

  1. Login request returns Set-Cookie: JSESSIONID=...
  2. Subsequent requests should contain:

Cookie: JSESSIONID=...

If the cookie is missing from the request, the browser is rejecting or not sending it (CORS/SameSite/credentials issue).

If the cookie is present but Spring still creates a new session, then the problem is on the server side. Common causes include:

  • Multiple application instances without session replication.
  • Session storage being cleared between requests.
  • A reverse proxy/load balancer changing session routing.
  • Custom filters or security configuration invalidating the session.
  • Different context paths causing Spring to look for a different session cookie.

The quickest way to narrow this down is to verify whether the browser is actually sending the same JSESSIONID back to the server. That will tell you whether you're dealing with a browser cookie problem or a server-side session management problem.

备选方案

The root cause is the SameSite cookie restriction in modern browsers. When your frontend (127.0.0.1:5500) and backend (192.168.x.x:8081) are on different origins, the browser blocks the session cookie — that ! warning in DevTools confirms this.

You need to fix three things together:


1. Set SameSite=None and Secure=true on the session cookie

In your application.properties:

server.servlet.session.cookie.same-site=None
server.servlet.session.cookie.secure=true
server.servlet.session.cookie.http-only=true

SameSite=None requires Secure=true — browsers will silently reject the cookie otherwise.


2. Enable HTTPS on your Spring Boot backend

Add to application.properties:

server.ssl.enabled=true
server.ssl.key-store=classpath:keystore.p12
server.ssl.key-store-password=yourpassword
server.ssl.key-store-type=PKCS12

Generate a self-signed cert:

keytool -genkeypair -alias springboot -keyalg RSA -keysize 2048 \
  -storetype PKCS12 -keystore keystore.p12 -validity 365

3. Send credentials: include on every frontend request

fetch("https://192.168.x.x:8081/api/dashboard", {
  method: "GET",
  credentials: "include"
});

Or with Axios:

axios.defaults.withCredentials = true;

4. Update CORS origins to https://

config.setAllowedOrigins(List.of(
    "https://127.0.0.1:5500",
    "https://192.168.178.31:5500"
));
config.setAllowCredentials(true);

Do not use setAllowedOriginPatterns("*") with allowCredentials(true) — Spring will throw an error.


Quickest alternative if you want to avoid HTTPS setup locally: serve your frontend through a reverse proxy (e.g., nginx) on the same host and port as your backend. Same origin means no SameSite restriction at all.

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章