소셜 로그인 구현

이전 글에서 소셜 로그인 구현을 위한 사전 준비를 하였다.

이제 스프링 부트에서 oauth2-client와 webflux로 소셜 로그인을 구현해볼 것이다.

소셜 로그인 화면은 Provider에서 제공하는거라 딱히 프론트쪽 구현 없이도 테스트 할 수 있다.

 

아래 그림은 카카오 디벨로퍼스에서 제공하는 카카오 로그인 흐름도이다.

구현 방법에 따라 다르겠지만 우선 본인이 구현한 방법에서는 백엔드에서 생각할 건 아래 두가지이다.

  • 리다이렉트 URL로 컨트롤러 호출 시 Provider 이름, 인증 코드 확인
  • 서비스 레이어에서 토큰 발급 후 이 토큰으로 유저 정보 받아오기 

이번 글에서는 컨트롤러를 호출하고 Provider 이름과 인증 코드를 확인하는 부분까지 진행한다.


사용 기술

  • Spring Boot 3.2.4 / gradle-kotlin
  • Java 17
  • webflux, oauth2-client

 

1. 프로젝트 사전 작업

1-1. 의존성 추가

아래 두 라이브러리의 의존성을 추가해준다.

webflux는 서버에서 HTTP 요청을 하기 위해서 사용하고, oauth2-client는 소셜 로그인을 구현하기 위해 사용한다.

// build.gradle.kts
// 소셜 로그인
implementation("org.springframework.boot:spring-boot-starter-oauth2-client")
implementation ("org.springframework.boot:spring-boot-starter-webflux")

1-2. application.yml 설정

oauth2-client를 사용하기 위해서는 아래처럼 yml 파일을 설정해줘야한다.

아래에서 # 으로 표시한 클라이언트 ID, 시크릿 키, 리다이렉트 URL 외에는 그대로 써도 무방하다.

변경한다면 client-name는 원하는대로 바꿔도 될듯하고, scope도 각자 설정한 부분만큼 설정하면 될 것 같다.

참고로 구글은 provider depth에 없는 이유는 기본적으로 설정이 되어 있어서다.

클라이언트 ID, 시크릿 키를 확인하는 위치는 이전 글을 참고하자.

spring:
  security:
    oauth2:
      client:
        registration:
          google:
            client-id: # 발급 받은 Client ID
            client-secret: # 발급 받은 시크릿 키
            redirect-uri: http://localhost:8080/api/auth/oauth2/google # 설정한 리다이렉트 URL
            scope:
              - email
              - profile
            client-name: 구글

          naver:
            client-id: # 발급 받은 Client ID
            client-secret: # 발급 받은 시크릿 키
            client-authentication-method: client_secret_post
            authorization-grant-type: authorization_code
            redirect-uri: # 설정한 리다이렉트 URL
            scope:
              - name
              - email
              - profile_image
            client-name: 네이버

          kakao:
            client-id: # 발급 받은 Client ID
            client-secret: # 발급 받은 시크릿 키
            client-authentication-method: client_secret_post
            authorization-grant-type: authorization_code
            scope:
              - profile_nickname
              - profile_image
              - account_email
            redirect-uri: # 설정한 리다이렉트 URL
            client-name: 카카오

        provider:
          naver:
            authorization-uri: https://nid.naver.com/oauth2.0/authorize
            token-uri: https://nid.naver.com/oauth2.0/token
            user-info-uri: https://openapi.naver.com/v1/nid/me
            user-info-authentication-method: header
            user-name-attribute: response # Naver 응답 값 resultCode, message, response 중 response 지정

          kakao:
            authorization-uri: https://kauth.kakao.com/oauth/authorize
            token-uri: https://kauth.kakao.com/oauth/token
            user-info-uri: https://kapi.kakao.com/v2/user/me
            user-info-authentication-method: header
            user-name-attribute: id # Kakao 응답 값 id, connected_at, properties, kakao_account 중 id 지정

2. 컨트롤러 호출 부분

컨트롤러를 호출하는 부분에 대해 설명해보려 한다.

Provider가 기본적으로 제공하는 화면이 있기 때문에 사용자를 그 화면을 호출하는 링크로 이동시키면 된다.

기본적인 형태는 아래와 같다.

{Provider가 제공하는 로그인 화면 주소}
?client_id={클라이언트 ID}
&redirect_uri={리다이렉트 URL}
&response_type=code

 

아래는 본인이 로컬에서 테스트할 때 사용하는 소셜 로그인 페이지 이동 링크이다.

2-1. 네이버 로그인 주소

기본적인 형태를 따른다.

https://nid.naver.com/oauth2.0/authorize?client_id=9NjBfBE6YM2diWzMy19n&redirect_uri=http://localhost:8080/api/auth/oauth2/naver&response_type=code

2-2. 카카오 로그인 주소

기본적인 형태를 따른다.

https://kauth.kakao.com/oauth/authorize?client_id=b88ca4129b6dcc848a022469f3d6ae1c&redirect_uri=http://localhost:8080/api/auth/oauth2/kakao&response_type=code

2-1. 구글 로그인 주소

구글 로그인 시 scope 값에 따라 제공하는 정보가 다르므로 스코프를 추가하고 나머지는 기본적인 형태를 따른다.

https://accounts.google.com/o/oauth2/v2/auth?client_id=241400103028-mj55qqtl4gv96o35fdavqm6fngb68ske.apps.googleusercontent.com&redirect_uri=http://localhost:8080/api/auth/oauth2/google&response_type=code&scope=email profile


3. 컨트롤러 구현

리다이렉트 URL로 컨트롤러를 호출하므로 GET 요청을 받는다.

또한 하나의 컨트롤러로 여러개의 Provider를 받기 위해 아래처럼 PathVariable로 다형적으로 받도록 설정했다.

또한 인증 코드는 Provider에서 리다이렉트 시 code라는 키 값의 쿼리 스트링으로 주므로 아래처럼 받았다.

소셜 로그인을 진행하고 성공 시 JWT를 쿠키에 담아 반환한다.

그리고 요청을 받는게 백엔드쪽 주소이므로 프론트 URL로 리다이렉트 시켜줬다.

AuthController

@Operation(summary = "소셜 로그인", description = "소셜 로그인 성공 시 쿠키를 반환합니다.")
@ApiResponse(responseCode = "200", description = "로그인에 성공",
    headers = {
        @Header(name = "Set-Cookie", description = "인증 쿠키")
    })
@ApiResponse(responseCode = "400", description = "잘못된 아이디 혹은 비밀번호")
@GetMapping("/oauth2/{provider}")
public ResponseEntity<ApiMessageResponse> oauth2Login(@PathVariable String provider, @RequestParam String code) {
    String jwtCookie = authFacade.oauth2Login(code, provider);
    return ResponseEntity
        .status(HttpStatus.FOUND)
        .header(HttpHeaders.SET_COOKIE, jwtCookie)
        .header(HttpHeaders.LOCATION, appConfig.getFrontDeployUrl())
        .body(new ApiMessageResponse("소셜 로그인에 성공했습니다."));
}

 

+ Recent posts