웹 브라우저에서는 보안상의 이유로, 다른 출처(origin)에서 자원을 요청하는 경우 제한한다.
이것을 **SOP(Same Origin Policy)** 동일 출처 정책이라 한다.
즉, 동일 출처(Same-Origin) 서버에 있는 리소스는 자유로이 가져올 수 있지만, 다른 출처(Cross-Origin) 서버의 리소스는 상호작용이 불가능하다는 말이다.
직역하면 "교차 출처 리소스 공유 정책"이라고 해석할 수 있는데, 여기서 교차 출처라고 하는 것은 (엇갈린) 다른 출처를 의미하는 것으로 보면 된다.
’서로 다른 출처에서 리소스를 공유하는 것’을 뜻한다.
출처(Origin)라는 것은 Protolcol과 Host 그리고 Port까지 모두 합친 URL을 의미한다
여기서 출처는 http://localhost:8080/ 과 같이 프로토콜 + 호스트 + 포트를 말한다. 여기서 하나라도 다르면 출처가 다르다고 말할 수 있다.
예를 들어, React의 3000포트에서 Spring Boot의 8080 포트로 API를 호출할 때, 별다른 설정을 하지 않았다면 출처가 다르므로 CORS 에러가 발생한다.
1) 클라이언트에서 HTTP요청의 헤더에 Origin을 담아 전달
기본적으로 웹은 HTTP 프로토콜을 이용하여 서버에 요청을 보내게 되는데, 이때 브라우저는 요청 헤더에 Origin 이라는 필드에 출처를 함께 담아 보내게 된다.
2) 서버는 응답헤더에 Access-Control-Allow-Origin을 담아 클라이언트로 전달
이후 서버가 이 요청에 대한 응답을 할 때 응답 헤더에 Access-Control-Allow-Origin이라는 필드를 추가하고 값으로 '이 리소스를 접근하는 것이 허용된 출처 url’을 내려보낸다.
3) 클라이언트에서 Origin과 서버가 보내준 Access-Control-Allow-Origin을 비교
결국 CORS 해결책은 서버의 허용이 필요하다.
서버에서 Access-Control-Allow-Origin 헤더에 허용할 출처를 기재해서 클라이언트에 응답하면 되는 것이다.
프록시 서버를 사용하면, Front에서 Back으로 요청을 프록시가 처리하여 브라우저가 같은 출처에서 통신하는 것처럼 보이게 할 수 있다.
프록시 서버는 클라이언트가 프록시 서버를 통해 다른 네트워크에 간접적으로 접속할 수 있게 해 준다.
쉽게 이해하자면 "중계서버"라고 이해하면 된다
npm install --save http-proxy-middleware
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function(app){
app.use(
'/main-dev', // 프록시를 적용할 경로
createProxyMiddleware( {
target: 'http://localhost:28081', // 요청이 전달될 백엔드 서버의 URL
changeOrigin: true,
})
);
};
'/main-dev'로 요청을 보내면 실제로는 http://localhost:28081의 백엔드 서버로 전달되게 된다.
포트주소는 각자 상황에 맞도록 설정한다.
import logo from './logo.svg';
import React, {useState, useEffect} from 'react';
import './App.css';
function App() {
const [message, setMessage] = useState("");
useEffect( () => {
fetch('/main-dev/devlog/jpa/selectUserAll', {method : "POST"})
.then(response => response.json())
.then(response => {
console.log(response);
setMessage(response.data[2].email);
});
},[])
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
{message}
</p>
</header>
</div>
);
}
export default App;
useState, useEffect는 React Hook이라는 개념인데 이후 포스팅에서 따로 정리하도록 하겠다.
이번글에서는 프록시를 설정하여 CORS 이슈를 해결하는 것에 집중해 보자.
public class SecurityConfig {
protected SecurityFilterChain configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
...
.cors(corsConfigurer -> corsConfigurer.configurationSource(corsConfigurationSource()))
...
}
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000", "http://127.0.0.1:3000")); // 허용할 도메인
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS")); // 허용할 HTTP 메서드
configuration.setAllowedHeaders(Arrays.asList("Authorization", "Content-Type")); // 허용할 헤더
//클라이언트가 CORS 요청에 인증 정보를 포함하도록 허용 - Ex) 쿠키를 전송하거나 인증 헤더(Authorization)를 포함할 수 있음
configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration); // 모든 경로에 CORS 정책 적용
return source;
}
}
React (프론트엔드)에서 오는 요청만을 허용하고, 특정 HTTP 메서드와 헤더를 사용할 수 있도록 한다.
이는 보안을 강화하면서도 React 애플리케이션이 백엔드 API와 원활하게 통신할 수 있도록 한다.
React(프론트엔드) 프록시 설정과 Spring(백엔드)의 SpringSecurity에 CORS설정을 추가한 후 React를 실행한 후 정상적으로 백엔드와 통신을 한다면 CORS설정은 완료된다.
React 설치 및 실행 / 프로젝트 구조 정리 (2) | 2025.01.30 |
---|---|
React 기본 개념 정리 (5) | 2025.01.23 |
댓글 영역