카카오 로그인이 요구사항에 들어왔다.
이미 로그인 기능을 세션 방식으로 구현했고 클라이언트와 연동만 마치면 된다고 생각했다.
당연하게 CORS가 발생할 걸 예상하며 미리 전부 열어두었다.
(프론트 도메인이 정해지면 변경하기 위함)
@Configuration
@RequiredArgsConstructor
public class WebConfig implements WebMvcConfigurer {
// ...
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("*)
.maxAge(3000L); // maxAge만큼 pre-flight request를 캐싱
}
}
그런데 처음 보는 기이한 현상..
카카오 로그인도 성공적이였고 기존에 예상했던 대로 Set-Cookie에서 JSSESIONID를 확인할 수 있었다.

하지만 application 탭에서 cookie를 확인해 보더라도 로컬에서 테스트 시에는 보였던 JSESSIONID가 보이지 않았다.🤔
CORS에 대한 생길 수 있는 부분은 다 열었다고 생각했는데 어떤 문제가 있는 걸까 구글링을 진행했다.
그 중에 2가지 자료를 통해 JSESSIONID를 application 탭에서 확인할 수 있게 되었다.🔥

결과적으로는 아래와 같이 구현했다.
server:
servlet:
session:
cookie:
secure: true
http-only: true
same-site: none
addCorsMappings 메서드를 아래와 같이 수정한다. @Configuration
@RequiredArgsConstructor
public class WebConfig implements WebMvcConfigurer {
//...
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:3000", "https://client.com")
.allowedMethods("GET", "POST", "PUT", "PATCH", "DELETE", "OPTION")
.allowCredentials(true)
.maxAge(3000L); // maxAge만큼 pre-flight request를 캐싱
}
}
동작을 하게 만들었지만, CORS와 Cookie의 옵션들에 대한 개념이 부족하다고 생각이 들었다.😳
CORS는 Cross Origin Resource Sharing의 약자이다.
다른 출처끼리 자원을 공유한다는 의미인데
하나의 예시를 들어보자.
https://client.com의 출처를 사용하고 있다.https://server.com의 출처를 사용하고 있다. client와 server는 서로 다른 출처를 가지고 있지만 서로 통신할 수 있는 것을 의미하는게 CORS이다.
다른 출처 접근을 막기 위해서 HTTP는 SOP(Same-origin policy, 동일 출처 정책)를 따르고 있다. 그렇기 때문에 Client와 Server는 서로 다른 출처에서 자원을 공유하기 위해서 따로 허용해주는 설정이 필요하다.
위에서 오버라이딩한 addCorsMappings 메서드가 바로 그러한 설정이다.
여기서 출처라는 개념이 굉장히 중요하다.
출처가 뭘까?
아래의 3가지를 합친 것을 출처라고 한다.
http://, https://client.com, server.com, ...80, 443, 8080, ...브라우저에서 CORS를 확인할 때, 문자열로 확인하기 때문에
Protocol, Host, Port가 정확히 일치해야 한다.
(Post중 기본 포트는 생략 가능)
동일한 출처에 대한 예시를 한 번 생각해보자.
1. http://test-domain.com vs https://test-domain.com
=> 다른 출처이다. Protocol이 다르기 때문
2. http://test-domain2.com vs http://test-domain.com
=> 다른 출처이다. Host가 다르기 때문
3. http://localhost:8080, http:// localhost:8081
=> 다른 출처이다. Port가 다르기 때문
4. http://localhost, http://127.0.0.1
=> 다른 출처이다. localhost와 127.0.0.1이 의미하는 건 같지만 브라우저에서는 문자열로 비교하기 때문에 다른 출처로 인식한다.
따라서 아래와 같이 허용하는 출처를 추가해주었다. 🫠
@Configuration
@RequiredArgsConstructor
public class WebConfig implements WebMvcConfigurer {
//...
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
/**
* 허용하는 출처 추가!
*/
.allowedOrigins("http://localhost:3000", "https://client.com")
/**
* 요청 시 허용하는 메서드들을 추가한다.
*/
.allowedMethods("GET", "POST", "PUT", "PATCH", "DELETE", "OPTION")
.allowCredentials(true)
.maxAge(3000L); // maxAge만큼 pre-flight request를 캐싱
}
}
🍪 CORS 쿠키 전송하기 (withCredentials 옵션) 블로그 글을 통해서 이해할 수 있었다.
Cross-Origin은 기본적으로 쿠키를 설정하거나 보낼 수 없다.
따라서 쿠키를 설정 혹은 요청에 실어서 보내기 위해서는 allowCredential을 true로 변경해 줘야 한다.
이때 주의해야할 점이 있다.
allowedOrigins("http://localhost:3000", "https://client.com")와 같이 구체적으로 출처를 명시해 줘야 한다.
클라이언트도 마찬가지로 credential에 대해서 허용을 해주는 로직을 필요하다.