SpringBoot

[SpringBoot] 로그인/세션 등 리액트 연동 문제 해결(1) - CORS, 리액트에서는 안 될 때, 스프링 부트와 AWS로 혼자 구현하는 웹 서비스

폭풍저그김탁구 2023. 1. 22. 14:21

스프링 부트와 AWS로 혼자 구현하는 웹서비스라는 책을 따라하며 백엔드 서버를 혼자 잘 구현했다.

그러고 프론트엔드로 구현해놓은 리액트와 연결하려 했다. (프론트는 다른 사람이 했음)

 

역시나~ 잘 될리가..ㅎ

백엔드의 진짜 문제는 서버 구동하면서 같다. 코딩은 백엔드의 10프로 정도만 하지 않나... 싶음...

 

우선 생긴 문제는 크게

1. CORS 오류

2. 스프링 시큐리티의 로그인 문제

이렇게다.

 

*

본 포스트는 제가 나름대로 이해하고 생각한 내용입니다. 실제 구동 방식과 다를 수도 있습니다.

실제 정확한 원리와 개념은 다른 포스트를 보세요... 부끄러워요...

 

*

책에서 나온 코드를 기준으로 작성되었습니다.

책 GitHub 주소: https://github.com/jojoldu/freelec-springboot2-webservice

 

 


 

1. CORS 오류

 

- 왜 오류가 떴을까?

: 서버는 localhost:8080, 리액트는 localhost:3000으로 접근했다.

CORS 자체가 이렇게 서버랑 클라이언트가 다를 때 생기는 문제가 아닌가. 그래서 클라이언트에서 접근하는 주소를 허용해야 한다.

 

- 해결 방법

우선 웹과, 스프링 시큐리티 두 곳에서 모두 CORS를 허용해줘야 한다.

로그인 리다이렉트를 보낼 때가 있으므로!

 

WebConfig.java

@Override
    public void addCorsMappings(CorsRegistry registry){
        registry.addMapping("/**")
                .allowedOrigins(
                		"http://localhost:8080", 
                		"http:{배포한 ec2 ip}:8080",
                        "http://localhost:3000"
                )
                .allowedMethods("GET", "POST", "PUT", "DELETE");
    }

나는 ec2로 배포해서 내 로컬 호스트, 리액트 로컬, ec2 이렇게 허용했다.

 

 

SecurityConfig.java

@Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();

        configuration.setAllowedOrigins(List.of("http://localhost:3000"));
        configuration.addAllowedHeader("*");
        configuration.addAllowedMethod("*");
        configuration.setAllowCredentials(true);

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

    }

나는 귀찮아서 와일드카드 썼는데 헤더랑 메소드 모두 위처럼 명확히 명시해주는 게 좋다.

여기서는 리액트 로컬만 추가해줬는데 추후에 리액트를 서버에 배포하면 주소 다시 수정해줘야 한다.

 

추가로 나는 apiController들에

@CrossOrigin("*")

이 어노테이션도 추가해줬는데 위 설정만으로 충분한 것 같다.

만약 api만 배포한다면 이 어노테이션만으로 충분할 것 같으나, 나는 시큐리티를 이용하므로 위 설정도 필요했다.

 

 


 

 

2. 카카오 로그인 관련 CORS 오류

 

요건 리액트 문제였다.

혹시 axios를 이용했다면 href로 보내기!

https://devtalk.kakao.com/t/rest-api-cors/114424

 

Rest API 로 로그인 구현 시 CORS 문제

rest API 로 로그인을 구현 중인데요. 아래와 같이 요청을 보내고 있습니다. `axios.get('https://kauth.kakao.com/oauth/authorize', { params: { client_id: process.env.REACT_APP_REST_API_KEY as string, redirect_uri: 'http://localhost:808

devtalk.kakao.com

 

 


 

3. 로그인 후 알 수 없는 페이지로 이동

 

이게 무슨 말이냐면... "/"에서 로그인을 시도하면 "/"로 잘 돌아와야 한다.

그런데 자꾸 이상한 알 수 없는 페이지로 들어가서 뭘까 싶었는데

 

":3000/" -> 로그인 요청 -> ":8080/"로 리다이렉트 이렇게 되는 거였다.,,

이건 스프링 시큐리티에서 자동으로 처리해주는 핸들링이라 스프링이 배포되어 있던 백엔드 서버로 리다렉 되던 거였음.

 

이런 경우엔 커스텀 핸들러를 따로 만들어야 한다.

 

 

SecurityConfig.java

.oauth2Login()
                    .defaultSuccessUrl("/login/success", true)
                    .successHandler(loginHandler)
                    .userInfoEndpoint()// 로그인 성공 이후 사용자 정보 가져올 때
                    .userService(customOAuth2UserService); //소셜 로그인 성공 후 인터페이스 구현체 등록(ex. sns에서 가져오고 싶은 사용자 정보 기능 명시 가능

이런 식으로 성공 시 돌아갈 url과 핸들러를 매핑해준 다음

 

loginHandler.java

@Component
public class LoginHandler extends SimpleUrlAuthenticationSuccessHandler {

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
                                        Authentication authentication) throws IOException {
        String url = "http://localhost:3000/";
        getRedirectStrategy().sendRedirect(request, response, url);
    }
}

이렇게 강제로 핸들링을 해줬다.

 

이거 코드만 봐도 쎄하다... 이렇게 url을 바로 매핑해주는 게 좀... 걸리다...

 

 


 

모른 척 하려고 했는데 역시 문제가 생겼다.

이렇게 해주면

8080 백엔드 서버에서는 세션이 유지가 되는데, 3000 리액트에서는 세션이 유지가 안 되는 거다.

결국 요청을 3000에서 해야 하는데 서로 맞지 않으니 이상한 거다.

 

어쩔 수 없이 jwt 토큰으로 통신을 해야 한다...

만약 리액트, 스프링 한 명이 다 해서 같은 주소로 배포하면 이 문제들은 없지 않을까 싶다.

 

나도 그렇게 할까 했다가 근본적인 문제가 해결이 안 되는 것 같아 그냥 방법을 틀기로 했다.

 

이건 2편에 이어 쓰도록 하겠습니다.