Spring Boot 2023 的 CORS 问题和 React App 的自定义标头

问题描述 投票:0回答:1

这是我实际的@Configuration类:

package com.example.churchbillboard2.configs;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@EnableWebMvc
public class CorsConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {

        registry.addMapping("/**")
            .allowedOrigins("*")
            .allowedMethods("PUT", "DELETE", "POST", "GET")
            .allowedHeaders("CustomAuth", "Authorization", "header3", "Origin", "Access-Control-Allow-Origin", "Content-Type",
            "Accept", "Origin, Accept", "X-Requested-With",
            "Access-Control-Request-Method", "Access-Control-Request-Headers")
            .exposedHeaders("CustomAuth", "Origin", "Content-Type", "Accept", "Authorization",
            "Access-Control-Allow-Origin", "Access-Control-Allow-Origin", "Access-Control-Allow-Credentials")
            .allowCredentials(true).maxAge(3600);
    }
}

这是我的 Spring Boot 目标控制器:

package com.example.churchbillboard2.controllers;

import org.springframework.web.bind.annotation.RestController;
import com.example.churchbillboard2.security.SessionToken;
import com.example.churchbillboard2.services.TimeManager;
import com.example.churchbillboard2.services.UserService;
import jakarta.servlet.http.HttpSession;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;

@RestController
@RequestMapping("/")
public class Login {
    private UserService userService;
    private TimeManager timeManager;
    private SessionTokenWrapper sessionTokenWrapper;

    public Login(UserService userService, TimeManager timeManager, SessionTokenWrapper sessionTokenWrapper) {
        this.userService = userService;
        this.timeManager = timeManager;
        this.sessionTokenWrapper = sessionTokenWrapper;
    }

    @PostMapping(value = "/login")
    public SessionToken getMethodName(@RequestBody LoginDTO user, HttpSession session) {
        SessionToken sessionToken = (userService.getUserByUserName(user) == null) ? new SessionToken("Invalid User")
                : new SessionToken(null);
        sessionTokenWrapper.setSessionToken(sessionToken.getSessionToken());
        System.out.println("sessionTokenWrapper.getSessionToken()");
        System.out.println(sessionTokenWrapper.getSessionToken());
        return sessionToken;
    }

    @PostMapping("/months")
    public AvailableMonthsWrapper getMethodName(@RequestHeader("CustomAuth") String headerValue,
            HttpSession session) {
                System.out.println("headerValue");
                System.out.println(headerValue);
        return (sessionTokenWrapper.validateToken(headerValue))
                ? new AvailableMonthsWrapper(timeManager.availableMonths())
                : new AvailableMonthsWrapper("Not Valid Session");
    }

    @GetMapping(value = "/")
    public String getHome() {
        return "Hi From Home";
    }
}

注意 PostMapping 有一个自定义标头“/months”。

现在我尝试使用从 React 上的两个自定义挂钩中获取,以保留 sessionTokenWrapper bean 的 SessionScope。

我的 React 客户端正在 3000 端口本地主机上运行。但我需要我的 SpringBoot 服务器能够处理来自任何地方的请求,无论源 IP、源端口是什么。

我的第一个 Hook 是这样的:

export const validateLogin = async (userName, password) => {
  const url = 'http://localhost:5000/login';
  const loginData = {
    username: userName,
    password: password,
  };

  const response = await fetch(url, {
    method: 'POST',
    credentials: 'include',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(loginData),
  });

  if (response.ok) {
    return await response.text();
  } else {
    throw new Error(`Request failed with status ${response.status}`);
  }
}

我的第二个钩子是(发送自定义标头的钩子):

export const fetchMonths = async (sessionToken) => {
    console.log('token: ', sessionToken);
    const url = 'http://localhost:5000/months';

    const response = await fetch(url, {
        method: 'POST',
        credentials: 'include', 
        headers: {
            'Content-Type': 'application/json',
            'CustomAuth': sessionToken, 
        },
    });

    if (response.ok) {
        return await response.text();
    } else {
        throw new Error(`Request failed with status ${response.status}`);
    }

};

我不断收到各种错误,从

开始

当包含凭据时,允许的来源不能设置为“”...*”

致现在的,也是我最痛苦的一个:

“从源“http://localhost:3000”获取“http://localhost:5000/login”的访问已被 CORS 策略阻止:对预检请求的响应未通过访问控制检查:无“访问”请求的资源上存在“-Control-Allow-Origin”标头。如果不透明响应满足您的需求,请将请求的模式设置为“no-cors”以在禁用 CORS 的情况下获取资源。”

我对 Spring Boot 还很陌生,这个 cors 配置很混乱。我究竟做错了什么?我需要什么才能让我的 Spring Boot 服务器与任何客户端进行自由通信,即使它发送自定义标头也是如此。 (这是因为我稍后也需要将其扩展到 Android 客户端)。

reactjs spring-boot cors httprequest custom-headers
1个回答
0
投票

对于任何有同样问题的人。我刚刚将 .allowedOrigins 更改为 .allowedOriginPatterns

registry.addMapping("/**")
            .allowedOriginPatterns("*") //here
            .allowedMethods("PUT", "DELETE", "POST", "GET") 
            .allowedHeaders("CustomAuth", "Authorization", "header3", "Origin", "Access-Control-Allow-Origin", "Content-Type",
            "Accept", "Origin, Accept", "X-Requested-With",
            "Access-Control-Request-Method", "Access-Control-Request-Headers")
            .exposedHeaders("CustomAuth", "Origin", "Content-Type", "Accept", "Authorization",
            "Access-Control-Allow-Origin", "Access-Control-Allow-Origin", "Access-Control-Allow-Credentials")
            .allowCredentials(true);
© www.soinside.com 2019 - 2024. All rights reserved.