我正在使用 Java Spring 框架和 Spring Security 开发 Web 应用程序的后端。我正在尝试使用 JWT 创建一个登录系统,方法是使用 Set-Cookie 标头将 JWT 访问令牌作为 cookie 从服务器发送到客户端。
当我用 Postman 在 localhost 上测试时,我似乎没有问题。然而,当尝试将 cookie 发送到另一台电脑上的客户端时,Set-Cookie 标头似乎被客户端拒绝。这是从客户端接收登录请求的逻辑,如果登录有效,则返回 JWT 访问令牌:
@PostMapping("/login")
public ResponseEntity<?> authenticate(HttpServletRequest request, HttpServletResponse response, @RequestBody AuthRequestDTO requestDTO){
// Verify the client's login (username and password)
AuthDTO responseDTO = authService.authenticate(requestDTO);
// Set JWT access token if the client's login details are valid
ResponseCookie cookieAccessToken = ResponseCookie.from("accessToken", responseDTO.getAccessToken())
.maxAge(Duration.ofMinutes(5))
.domain(request.getRemoteAddr())
.sameSite("Lax")
.secure(false)
.httpOnly(true)
.build();
// Add access token as "Set-Cookie" key-value in HTTP response header.
response.addHeader(HttpHeaders.SET_COOKIE, cookieAccessToken.toString());
log.info("Access Token Cookie : " + cookieAccessToken.toString());
return ResponseEntity.ok().body(null);
}
我觉得重点是关于ResponseCookie方法。我尝试过更改许多方法选项,但无济于事。如果有人曾经通过 HTTP 连接(不是 HTTPS - 由于代码处于早期开发阶段)发送 cookie,我将不胜感激。作为参考,这是我的 Spring Security 配置设置(AUTH_WHITELIST 允许访问登录 API,而无需访问令牌,jwtAuthenticationFilter 是我的 JWT 自定义实现的 spring bean 组件):
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception{
http.csrf((csrf) -> csrf.disable())
.headers((header)->header.frameOptions((fo)->fo.sameOrigin()))
.authorizeHttpRequests((authorize) -> authorize
.requestMatchers(AUTH_WHITELIST).permitAll()
.requestMatchers("/api/admin").hasAnyRole(ADMIN_MAIN.name(), ADMIN_SUB.name())
.requestMatchers("/api/file").hasAnyRole(ADMIN_MAIN.name(), ADMIN_SUB.name())
.requestMatchers("/**").hasAnyRole(ADMIN_MAIN.name(), ADMIN_SUB.name(), USER_ENTERPRISE.name(), USER_INDIVIDUAL.name(), VISITOR.name())
.anyRequest().authenticated());
http.sessionManagement((sessionManagement) -> sessionManagement
.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authenticationProvider(authenticationProvider)
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
http.logout((logout) -> logout.logoutUrl("/api/auth/logout").addLogoutHandler(logoutHandler)
.logoutSuccessHandler((request, response, authentication) -> SecurityContextHolder.clearContext()));
return http.build();
}
我尝试从多个客户端访问登录 API。我尝试从另一台电脑访问 Google Chrome、Mozilla Firefox 和 Postman 上的登录 API(即与服务器不同的 IP 地址)。编辑:我确实在单独的文件中配置了 CORS。
@Override
public void addCorsMappings(CorsRegistry registry){
// addMapping configures the URL patterns to which the CORS configuration applies. In this case, it is set to apply to all paths ("/**").
// allowedOrigins method sets the list of origins (domains) allowed to access resources on the server. In this case, the server accepts requests from any domain ("*").
// allowedMethods method sets the HTTP methods that are allowed for cross-origin requests.
registry.addMapping("/**")
.allowedOriginPatterns("*")
.allowCredentials(true)
.allowedMethods("GET", "POST", "PUT", "DELETE");
}
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowCredentials(true) // Allow cookies
.maxAge(3600);
}
};
}
request.getRemoteAddr()
进行测试,而不是使用
localhost
ResponseCookie cookieAccessToken = ResponseCookie.from("accessToken", responseDTO.getAccessToken())
.maxAge(Duration.ofMinutes(5))
.domain("yourdomain.com") // Set your domain here
.path("/") // Set the path if necessary
.sameSite("Lax")
.secure(false)
.httpOnly(true)
.build();