Backend/springboot

[SpringBoot] 스프링부트 구글 로그인 API REST 방식으로 구현하기

설기똥꼬 2023. 1. 11. 23:59

저번에 작성한 구글 로그인 API 로직을 바탕으로 공식 문서와 여러 레퍼런스를 참고하여 실제로 구글 로그인 API를 구현해 볼 것이다.

현재 라이징테스트 원티드 클론 코딩 프로젝트 중 구글 로그인을 맡게 되어 명확하게 이해하고 넘어가고 싶어 글을 작성하게 되었다.

 

0. 소셜로그인 로직

출처 : luiseok.com

 

1. 구글 OAuth API 프로젝트 환경 구성

 

1) 우선 사용자에게 보여질 Oauth 동의 화면을 구성한다.

  • 사용자 인증 정보 메뉴 선택
  • 사용자 인증 정보 만들기 클릭
  • OAuth Client ID 만들기 클릭

 

2) 구글의 어떤 사용자 데이터까지 접근할 것인지 범위를 지정한다.

 email, profile까지 지정하였다. 완료되면 사용자 Oauth 동의 화면이 구성된다.

 

 

3) OAuth api에 액세스하기 위해 사용자 인증 정보를 발급해야 한다.

  1. 옆 메뉴에서 사용자 인증 정보 클릭
  2. 사용자 인증 정보 만들기 클릭
  3. OAuth 클라이언트 ID 만들기 클릭
  4. 위 화면에서 애플리케이션 유형 -> 웹 애플리케이션 선택
  5. 승인된 자바스크립트 원본 및 Redirection URI 입력

 

  → 프로젝트에서 redirect할 주소로 localhost:9000/users/login/redirect으로 설정

(로컬서버인 경우 로컬호스트 입력이 가능하고 별도 서버를 둔 경우에는 해당 서버의 Public IP를 입력할 수 있다. 대신, login 요청하는 URL의 Root 주소여야 한다. 포트 번호도 마찬가지이다. 현재 진행 중인 프로젝트의 포트 번호는 9000!)

 

승인된 리디렉션 URI : 구글 로그인 이후 사용자의 AuthCode를 전달받는 URL 입력

 

 

4) 해당 과정을 거치면 아래와 같이 사용자 인증 정보가 발급된다.

대시보드에서 OAuth 클라이언트 ID의 이름을 누르게 되면 우측에 위와 같이 클라이언트 ID, 클라이언트 보안 비밀(Secret ID) 가 존재하는데, 이를 알고 있어야 로그인 API를 사용할 수 있다.

 

구글 로그인 API 사용 설정은 모두 마쳤다.

 

 

2. REST API 구현

  • SNS 소셜 로그인 프로세스
    • 로그인 최초 요청 처리 (”/users/googleLogin”)
      • 첫번째로 사용자가 웹사이트의 로그인 화면에서 특정한 소셜 로그인 버튼을 클릭하게 되는데, 먼저 이 요청을 처리해야 한다.
      • 이 요청은 정해진 형식으로 URL을 갖춰서 소셜 로그인 페이지로 리다이렉트하는 과정으로 처리한다.
    • 소셜 로그인 페이지에서 로그인한 이후 승인된 리디렉션 URI로 리다이렉트(”/users/login/redirect”)
      • 이때 해당 API 서버로부터 1회용 access code를 받게 되는데, 이 코드를 이용해 api 서버로부터 access token과 refresh token을 받게 된다.
    • 이 access token을 이용해서 인가 처리를 실행하며, 소셜 서버로부터 사용자의 추가 정보를 요청할때도 이 access token을 사용하여 정보를 받아올 수 있다.
  • 소셜 로그인을 구현하기 위해서는 해당 서드파티와 반드시 정해진 형식에 맞춰서 response/request를 진행해야 한다. 
    • REST API를 구현할 예정이므로 HTTP/REST 규약 부분을 참고해서 개발하였다.

 

⬇️ 하단 사이트 반드시 참고

https://developers.google.com/identity/protocols/oauth2/web-server#libraries

 

웹 서버 애플리케이션용 OAuth 2.0 사용  |  Authorization  |  Google Developers

이 페이지는 Cloud Translation API를 통해 번역되었습니다. Switch to English 의견 보내기 웹 서버 애플리케이션용 OAuth 2.0 사용 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분

developers.google.com

 

전체적인 틀, 과정은 위의 공식 문서에서 확인할 수 있다.

 

 

1단계 : 승인 매개변수 설정하기 (GoogleOauth 클래스 상세구현)

첫번째 단계는 승인 요청을 생성하여 애플리케이션을 식별하는 매개변수를 설정하고 사용자에게 애플리케이션에 부여하라는 요청을 정의합니다.

## 공식문서
Google의 OAuth 2.0 엔드포인트는 https://accounts.google.com/o/oauth2/v2/auth에 있습니다. 이 엔드포인트는 HTTPS를 통해서만 액세스할 수 있습니다. 일반 HTTP 연결은 거부됩니다.
Google 승인 서버는 웹 서버 애플리케이션에 다음과 같은 쿼리 문자열 매개변수를 지원합니다.

# 매개변수
client_id (필수)
애플리케이션의 클라이언트 ID입니다.

redirect_uri (필수)
사용자가 승인 흐름을 완료한 후 API 서버가 사용자를 리디렉션하는 위치를 결정합니다. 이 값은 클라이언트의 API에서 구성한 OAuth 2.0 클라이언트에 대해 승인된 리디렉션 URI 중 하나와 정확히 일치해야 합니다.

response_type (필수)
Google OAuth 2.0 엔드포인트에서 승인 코드를 반환할지 여부를 결정합니다. 웹 서버 애플리케이션의 매개변수 값을 code로 설정합니다.

scope (필수)
애플리케이션이 사용자를 대신하여 액세스할 수 있는 리소스를 식별하는 공백으로 구분된 범위 목록입니다. 이러한 값은 Google이 사용자에게 표시하는 동의 화면에 알립니다. 범위를 사용하면 애플리케이션이 필요한 리소스에 대한 액세스만 요청하는 동시에 사용자가 애플리케이션에 부여하는 액세스 양을 제어할 수 있습니다. 

access_type (권장)
사용자가 브라우저에 없을 때 애플리케이션이 액세스 토큰을 새로고침할 수 있는지 여부를 나타냅니다. 유효한 매개변수 값은 기본값인 online와 offline입니다. 이 값은 애플리케이션이 처음 승인 코드를 토큰으로 교환할 때 갱신 토큰 및 액세스 토큰을 반환하도록 Google 승인 서버에 지시합니다.

state (권장)
애플리케이션이 승인 요청과 승인 서버의 응답 간에 상태를 유지하는 데 사용하는 문자열 값을 지정합니다. 이 매개변수를 사용하여 사용자를 애플리케이션의 올바른 리소스로 안내하거나, nonce를 전송하고, 크로스 사이트 요청 위조를 완화할 수 있습니다. redirect_uri을 추측할 수 있으므로 state 값을 사용하면 수신 연결이 인증 요청의 결과임을 보장할 수 있습니다.

application.yml에 발급받은 client id, client secret key 등을 등록해준다.

노출되면 보안 상 문제가 생기므로 코드에 직접 추가하지 않고 yml 파일에 불러와서 사용해준다.

 

작성한 application.yml은 다음과 같다.

google:
  auth:
    url: 'https://oauth2.googleapis.com'
    scope: 'profile,email,openid'
  login:
    url: 'https://accounts.google.com'
  redirect:
    uri: 'http://localhost:9000/users/login/redirect'
  client:
    id: ' '
  secret: ' '

 

 

2단계 : Google OAuth 2.0 서버로 리디렉션 & 사용자 동의 요청

이 단계에서는 사용자가 애플리케이션에 요청된 액세스 권한을 부여할지 결정한다.

서버 측에서는 구글 소셜 로그인 페이지로 리디렉션하려면 어떻게 URL을 구성해야 하는지 확인한다.

Google의 OAuth 2.0 서버는 사용자를 인증하고 애플리케이션이 요청된 범위에 액세스할 수 있도록 사용자의 동의를 얻는다. 지정한 리디렉션 URL을 사용하여 응답이 애플리케이션에 다시 전송된다.

 

URL을 구성하기 위해 Config 파일에 코드를 추가해주었다.

@Component
    public class ConfigUtils {
        @Value("${google.auth.url}")
        private String googleAuthUrl;

        @Value("${google.login.url}")
        private String googleLoginUrl;

        @Value("${google.redirect.uri}")
        private String googleRedirectUrl;

        @Value("${google.client.id}")
        private String googleClientId;

        @Value("${google.secret}")
        private String googleSecret;

        @Value("${google.auth.scope}")
        private String scopes;

        public String googleInitUrl() {
            Map<String, Object> params = new HashMap<>();
            params.put("client_id", getGoogleClientId());
            params.put("redirect_uri", getGoogleRedirectUri());
            params.put("response_type", "code");
            params.put("scope", getScopeUrl());
			
            // 파라미터를 형식에 맞춰 구성해주는 함수
            String paramStr = params.entrySet().stream()
                    .map(param -> param.getKey() + "=" + param.getValue())
                    .collect(Collectors.joining("&"));

            return getGoogleLoginUrl()
                    + "/o/oauth2/v2/auth"
                    + "?"
                    + paramStr;
        }

        public String getGoogleAuthUrl() {
            return googleAuthUrl;
        }

        public String getGoogleLoginUrl() {
            return googleLoginUrl;
        }

        public String getGoogleClientId() {
            return googleClientId;
        }

        public String getGoogleRedirectUri() {
            return googleRedirectUrl;
        }

        public String getGoogleSecret() {
            return googleSecret;
        }

        // scope의 값을 보내기 위해 띄어쓰기 값을 UTF-8로 변환하는 로직 포함
        public String getScopeUrl() {
            return scopes.replaceAll(",", "%20");
        }
    }

 https://accounts.google.com/o/oauth2/v2/auth?scope=profile&response_type=code&client_id="할당받은id"&redirect_uri="access token 처리" 로 Redirect URL을 생성하는 로직을 구성한다.

application.yml에 @Value에 해당하는 값과 일치하지 않게 적으면 인식을 못한다.

 

 

 

3단계 : 소셜 로그인 이후 요청 처리

이전에 구글에 등록해뒀던 redirect api를 controller에서 개발한다.

  • 소셜 로그인 결과로 받아온 일회성 코드 (상단의 사진)를 보내서 서드파티 (Thrid Party, 제3자 즉 구글)로부터 액세스 토큰을 받아오고, 그 액세스 토큰을 다시 보내 서드파티에 저장된 사용자 정보를 받아오는 일련의 과정을 거칠 것이다.
  • 그 과정의 결과로 다시 서버에 정보를 요청할때 필요한 accessToken, 개발 중인 서버에서 회원 인가처리를 할 jwtToken, 그리고 추후에 조회등에 필요한 userIdx등의 정보를 받아올 것이다.

서버와 통신하기 위한 소셜 로그인 model을 생성한다.

아래부터 나오는 코드들은 메이쁘님의 코드를 공부하며 참고했다. 정말 감사합니다 ,,,

 

[Spring Boot] Google 로그인 REST API 로만 구현해보기!(코드, 스샷)

안녕하세요? Spring Boot와 Java를 이용해서 쉽고 간단하게 구글 로그인하는 API를 구현해봤습니다. 여러 블로그 및 공식 문서를 참고했습니다. https://developers.google.com/identity/protocols/oauth2/web-server 웹

maivve.tistory.com

 

먼저 일회성 토큰을 받은 후 해당 일회성 토큰을 가지고 Access Token을 발급받기 위한 Request 모델이다.

@Getter
@Setter
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class GoogleLoginReq {
    private String clientId;    // 애플리케이션의 클라이언트 ID
    private String redirectUri; // Google 로그인 후 redirect 위치
    private String clientSecret;    // 클라이언트 보안 비밀
    private String responseType;    // Google OAuth 2.0 엔드포인트가 인증 코드를 반환하는지 여부
    private String scope;   // OAuth 동의범위
    private String code;
    private String accessType;  // 사용자가 브라우저에 없을 때 애플리케이션이 액세스 토큰을 새로 고칠 수 있는지 여부
    private String grantType;
    private String state;
    private String includeGrantedScopes;    // 애플리케이션이 컨텍스트에서 추가 범위에 대한 액세스를 요청하기 위해 추가 권한 부여를 사용
    private String loginHint;   // 애플리케이션이 인증하려는 사용자를 알고 있는 경우 이 매개변수를 사용하여 Google 인증 서버에 힌트를 제공
    private String prompt;  // default: 처음으로 액세스를 요청할 때만 사용자에게 메시지가 표시
}

 

다음은 일회성 토큰을 통해 얻은 Response 모델이다.

@Data
@AllArgsConstructor
@NoArgsConstructor
public class GoogleLoginRes {
    private String accessToken; // 애플리케이션이 Google API 요청을 승인하기 위해 보내는 토큰
    private String expiresIn;   // Access Token의 남은 수명
    private String refreshToken;    // 새 액세스 토큰을 얻는 데 사용할 수 있는 토큰
    private String scope;
    private String tokenType;   // 반환된 토큰 유형(Bearer 고정)
    private String idToken;
}

 

다음으로 구글로 액세스 토큰을 활용해 JWT의 Payload 부분인 구글에 등록된 사용자 정보에 관한 model이다.

@Data
@NoArgsConstructor
public class GoogleLoginDto {

    private String iss;
    private String azp;
    private String aud;
    private String sub;
    private String email;
    private String emailVerified;
    private String atHash;
    private String name;
    private String picture;
    private String givenName;
    private String familyName;
    private String locale;
    private String iat;
    private String exp;
    private String alg;
    private String kid;
    private String typ;

}

 

그리고 각각 클라이언트의 정보에 관해 요청할 값들, jwtToken과 accessToken등이 담겨져 반환할 객체이다.

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class GetGoogleReq {
    private String nickName;
    private String email;
    private String phoneNum;
    private String pwd;
    private String profileImgUrl;
}
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class GetGoogleRes {

    private String jwtToken;
    private int userIdx;
    private String accessToken;
    private String tokenType;
}

 

1) /users/googleLogin

Service 구현 없이 하나의 Controller function 안에서 로직을 구현하였다.

/**
     * 구글로그인 API
     * [GET] /users/googleLogIn
     * @return BaseResponse<PostLoginRes>
     */
    @ResponseBody
    @GetMapping("/googleLogin")
    public ResponseEntity<Object> moveGoogleInitUrl() {
        String authUrl = configUtils.googleInitUrl();
        URI redirectUri = null;
        try {
            redirectUri = new URI(authUrl);
            HttpHeaders httpHeaders = new HttpHeaders();
            httpHeaders.setLocation(redirectUri);
            return new ResponseEntity<>(httpHeaders, HttpStatus.SEE_OTHER);
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }

        return ResponseEntity.badRequest().build();
    }

구글 로그인 페이지 창으로 인도하는 API이다.

client Id, redirect Url, response type, scope과 같은 파라미터를 형식에 맞춰서 구성을 한뒤, yml에 설정한 redirect Login Url과 함께 담아 반환해준다. 즉 구글 로그인 페이지가 보여지게 한다.

상단의 redirectUri는 http Header에 담아진다. 이를 ResponseEntity 형식으로 감싸주고 반환한다.

 

HttpHeaders

  • Header에 원하는 방식으로 key-value값을 설정해서 보낼 수 있는 객체이다.
  • 클라이언트와 서버가 요청 또는 응답으로 부가적인 정보를 전송할 수 있도록 한다.

ResponseEntity

  • 일반적인 API는 반환하는 리소스에 Value만 있지 않으며, 상태 코드, 응답 메세지 등이 포함될 수 있다.
  • ResponseEntity는 client가 보내는 여러가지 응답 내용을 규격에 맞게 한번 감싸주는 역할을 한다.
  • 같은 역할로는 @ResponseBody 어노테이션이 있다.
  • HttpEntity를 상속받고 있는 클래스이다.

 

Postman으로 테스트해본 결과,

  • localhost:9000/users/googleLogin으로 request하면 일련의 과정을 거쳐 소셜 로그인 페이지가 렌더링된다.

 

브라우저에서 확인해보면,

  • 곧바로 소셜 로그인 페이지로 리다이렉트되어 저장되어있는 프로필 페이지가 렌더링되는 것을 확인할 수 있다.

 

  • 프로필을 선택하고 나면 이전에 남은 로그인 처리를 진행할 redirect_uri로 지정했던 url로 리다이렉트된다.
  • 상단의 코드 파라미터가 추후에 사용할 일회성 코드이다.

 

2) /users/login/redirect

/**
     * Social Login API Server 요청에 의한 callback 을 처리
     * @param  code API Server 로부터 넘어오는 code
     * @return GetGoogleRes
     */
    @ResponseBody
    @GetMapping("/login/redirect")
    public BaseResponse<GetGoogleRes> redirectGoogleLogin(@RequestParam("code") String authCode) {
        // HTTP 통신을 위해 RestTemplate 활용
        RestTemplate restTemplate = new RestTemplate();
        GoogleLoginReq requestParams = GoogleLoginReq.builder()
                .clientId(configUtils.getGoogleClientId())
                .clientSecret(configUtils.getGoogleSecret())
                .code(authCode)
                .redirectUri(configUtils.getGoogleRedirectUri())
                .grantType("authorization_code")
                .build();

        try {
            // Http Header 설정
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            HttpEntity<GoogleLoginReq> httpRequestEntity = new HttpEntity<>(requestParams, headers);
            ResponseEntity<String> apiResponseJson = restTemplate.postForEntity(configUtils.getGoogleAuthUrl() + "/token", httpRequestEntity, String.class);

            // ObjectMapper를 통해 String to Object로 변환
            ObjectMapper objectMapper = new ObjectMapper();
            objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
            objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); // NULL이 아닌 값만 응답받기(NULL인 경우는 생략)
            GoogleLoginRes googleLoginResponse = objectMapper.readValue(apiResponseJson.getBody(), new TypeReference<GoogleLoginRes>() {});

            // 사용자의 정보는 JWT Token으로 저장되어 있고, Id_Token에 값을 저장한다.
            String jwtToken = googleLoginResponse.getIdToken();

            // JWT Token을 전달해 JWT 저장된 사용자 정보 확인
            String requestUrl = UriComponentsBuilder.fromHttpUrl(configUtils.getGoogleAuthUrl() + "/tokeninfo").queryParam("id_token", jwtToken).toUriString();

            String resultJson = restTemplate.getForObject(requestUrl, String.class);

            // 랜덤 문자열
            String alphaNum = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
            String Num = "0123456789";
            int alphaNumLength = alphaNum.length();
            int numLength = Num.length();

            Random random = new Random();

            StringBuffer code = new StringBuffer();
            for (int i = 0; i < 8; i++) {
                code.append(alphaNum.charAt(random.nextInt(alphaNumLength)));
            }

            StringBuffer phoneNum = new StringBuffer();
            phoneNum.append("010");
            for (int i = 0; i < 8; i++) {
                phoneNum.append(alphaNum.charAt(random.nextInt(numLength)));
            }

            if(resultJson != null) {

                GoogleLoginDto userInfoDto = objectMapper.readValue(resultJson, new TypeReference<GoogleLoginDto>() {});

                GetGoogleReq getGoogleReq = new GetGoogleReq(userInfoDto.getName(), userInfoDto.getEmail(), phoneNum.toString(), code.toString(), userInfoDto.getPicture());
                GetGoogleRes getGoogleRes = userService.createSocialUser(getGoogleReq);
                    getGoogleRes.setAccessToken(googleLoginResponse.getAccessToken());
                    getGoogleRes.setTokenType(googleLoginResponse.getTokenType());
                return new BaseResponse<>(getGoogleRes);

            }
            else {
                throw new Exception("Google OAuth failed!");
            }

        }
        catch (Exception e) {
            e.printStackTrace();
        }
        return new BaseResponse<>(BAD_REQUEST);
    }

 

전체 코드이다. 부분별로 나눠서 살펴보자.

 

// HTTP 통신을 위해 RestTemplate 활용
        RestTemplate restTemplate = new RestTemplate();
        GoogleLoginReq requestParams = GoogleLoginReq.builder()
                .clientId(configUtils.getGoogleClientId())
                .clientSecret(configUtils.getGoogleSecret())
                .code(authCode)
                .redirectUri(configUtils.getGoogleRedirectUri())
                .grantType("authorization_code")
                .build();

사용자가 로그인하려고 클릭을 하면 구글에서 accessToken을 발급받기 위해 미리 설정한 uri로 리다이렉트된다.

try문 전까지 보면 우선 HTTP 통신을 위해 RestTemplate을 활용하였다. (보통 Config에 함수를 추가해준다.)

그리고 일회성 토큰으로 accessToken을 발급받기 위해 GoogleLoginReq 바디에 알맞게 client Id, clientSecret, auth code, redirect Uri, 권한 코드와 같은 파라미터들을 담아준다.

 

// HTTP 통신을 위해 RestTemplate 활용
        RestTemplate restTemplate = new RestTemplate();
        GoogleLoginReq requestParams = GoogleLoginReq.builder()
                .clientId(configUtils.getGoogleClientId())
                .clientSecret(configUtils.getGoogleSecret())
                .code(authCode)
                .redirectUri(configUtils.getGoogleRedirectUri())
                .grantType("authorization_code")
                .build();

try문부터 살펴보면, Http 헤더를 설정한다. 헤더에 상단에 파라미터를 담은 모델, 즉 일회성 토큰을 통하여 accessToken을 발급받을 준비를 한다.

 

// ObjectMapper를 통해 String to Object로 변환
            ObjectMapper objectMapper = new ObjectMapper();
            objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
            objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); // NULL이 아닌 값만 응답받기(NULL인 경우는 생략)
            GoogleLoginRes googleLoginResponse = objectMapper.readValue(apiResponseJson.getBody(), new TypeReference<GoogleLoginRes>() {});

            // 사용자의 정보는 JWT Token으로 저장되어 있고, Id_Token에 값을 저장한다.
            String jwtToken = googleLoginResponse.getIdToken();

            // JWT Token을 전달해 JWT 저장된 사용자 정보 확인
            String requestUrl = UriComponentsBuilder.fromHttpUrl(configUtils.getGoogleAuthUrl() + "/tokeninfo").queryParam("id_token", jwtToken).toUriString();

            String resultJson = restTemplate.getForObject(requestUrl, String.class);

ObjectMapper를 활용해서 String을 Object로 반환해주고,

일회성 토큰을 통해 얻은 Access Token이 담긴 Response 모델을 읽어온다.

 

이 모델에 담긴 사용자의 Id Token값을 따로 저장한다.

이 Jwt Token을 Uri에 전달하여 저장된 사용자 정보인지 확인을 하고, Object값으로 result값을 받아온다.

 

if(resultJson != null) {

                GoogleLoginDto userInfoDto = objectMapper.readValue(resultJson, new TypeReference<GoogleLoginDto>() {});

                GetGoogleReq getGoogleReq = new GetGoogleReq(userInfoDto.getName(), userInfoDto.getEmail(), phoneNum.toString(), code.toString(), userInfoDto.getPicture());
                GetGoogleRes getGoogleRes = userService.createSocialUser(getGoogleReq);
                    getGoogleRes.setAccessToken(googleLoginResponse.getAccessToken());
                    getGoogleRes.setTokenType(googleLoginResponse.getTokenType());
                return new BaseResponse<>(getGoogleRes);

            }
            else {
                throw new Exception("Google OAuth failed!");
            }

result값이 null이 아니라면 objectMapper를 통해 GoogleLoginDto에 사용자의 정보 (userInfoDto)를 담아온다.

DB에 반영하기 위해 userInfoDto에 있는 값을 활용하여 GetGoogleReq를 생성한다.

이번 프로젝트에서는 유저의 비밀번호와 전화번호는 not null로 설정했기에 랜덤으로 값을 생성해준다.

 

다시 한번 localhost:9000/users/googleLogin에 들어가 로그인을 시도해보면..

다음과 같이 잘 되는 것을 확인할 수 있다!

유저를 생성할 때 사용한 jwtService의 createJwt 메소드를 사용해서 jwtToken도 발급해주었다.

DB에도 정상적으로 잘 반영된 것을 확인할 수 있다!

 

저번 GetIT 프로젝트에서도 구글, 네이버 소셜 로그인을 구현했으나 내 담당 API가 아니었고, 그렇기에 이번 라이징 테스트 때 꼭 구현해보고자 다짐했었다.

차근차근 공식 문서와 멋진 블로그 선배림들 자료들을 통하여 단계별로 짚고 넘어가서 확실히 이해할 수 있었다!

이번 이어달리기 프로젝트 때 맡게 된다면 프로젝트 구조를 명확히 하여 util, Controller, Service단 각각 역할을 구분지어 가독성 있는 API를 짜고 싶다. 

 

# 레퍼런스
https://maivve.tistory.com/336
https://mslilsunshine.tistory.com/171
https://wonit.tistory.com/308