[토이프로젝트] 감정일기장-3 : OAuth2 / Oidc 로그인 프로세스

onlydev7777·2024년 9월 13일
post-thumbnail

OAuth2 로그인 프로세스

OAuth2 로그인 프로세스

1. SignIn.jsx

  • axios나 ajax는 CORS 이슈로 인해 href 로 처리해서 redirect 받는다.
  const oauth2Login = (provider) => {
    window.location.href = "http://localhost:9001/oauth2/authorization/"
        + provider;
  }

2. OAuth2AuthorizationRequestRedirectFilter

	private void sendRedirectForAuthorization(HttpServletRequest request, HttpServletResponse response,
			OAuth2AuthorizationRequest authorizationRequest) throws IOException {
		if (AuthorizationGrantType.AUTHORIZATION_CODE.equals(authorizationRequest.getGrantType())) {
			this.authorizationRequestRepository.saveAuthorizationRequest(authorizationRequest, request, response);
		}
		this.authorizationRedirectStrategy.sendRedirect(request, response,
				authorizationRequest.getAuthorizationRequestUri());
	}

3. OAuth2LoginAuthenticationFilter

  • 사용자 로그인 성공 이후 OAUth2 Provider 로 부터 발급 받은 임시코드를 통해 Access-Token 을 요청 하는 필터
  • 발급 받은 Access-Token 으로 사용자 정보(UserInfo)를 요청하는 필터
  • 응답 받은 사용자 정보(UserInfo) 를 토대로 DB 확인 후 Find Or Save 처리
  • 모든 처리가 완료되면 클라이언트에게 Access-Token 과 Refresh-Token 을 발급해서 302 리다이렉트 응답
	@Override
	public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
			throws AuthenticationException {
		MultiValueMap<String, String> params = OAuth2AuthorizationResponseUtils.toMultiMap(request.getParameterMap());
		if (!OAuth2AuthorizationResponseUtils.isAuthorizationResponse(params)) {
			OAuth2Error oauth2Error = new OAuth2Error(OAuth2ErrorCodes.INVALID_REQUEST);
			throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
		}
		OAuth2AuthorizationRequest authorizationRequest = this.authorizationRequestRepository
			.removeAuthorizationRequest(request, response);
		if (authorizationRequest == null) {
			OAuth2Error oauth2Error = new OAuth2Error(AUTHORIZATION_REQUEST_NOT_FOUND_ERROR_CODE);
			throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
		}
		String registrationId = authorizationRequest.getAttribute(OAuth2ParameterNames.REGISTRATION_ID);
		ClientRegistration clientRegistration = this.clientRegistrationRepository.findByRegistrationId(registrationId);
		if (clientRegistration == null) {
			OAuth2Error oauth2Error = new OAuth2Error(CLIENT_REGISTRATION_NOT_FOUND_ERROR_CODE,
					"Client Registration not found with Id: " + registrationId, null);
			throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
		}
		// @formatter:off
		String redirectUri = UriComponentsBuilder.fromHttpUrl(UrlUtils.buildFullRequestUrl(request))
				.replaceQuery(null)
				.build()
				.toUriString();
		// @formatter:on
		OAuth2AuthorizationResponse authorizationResponse = OAuth2AuthorizationResponseUtils.convert(params,
				redirectUri);
		Object authenticationDetails = this.authenticationDetailsSource.buildDetails(request);
		OAuth2LoginAuthenticationToken authenticationRequest = new OAuth2LoginAuthenticationToken(clientRegistration,
				new OAuth2AuthorizationExchange(authorizationRequest, authorizationResponse));
		authenticationRequest.setDetails(authenticationDetails);
		OAuth2LoginAuthenticationToken authenticationResult = (OAuth2LoginAuthenticationToken) this
			.getAuthenticationManager()
			.authenticate(authenticationRequest);
		OAuth2AuthenticationToken oauth2Authentication = this.authenticationResultConverter
			.convert(authenticationResult);
		Assert.notNull(oauth2Authentication, "authentication result cannot be null");
		oauth2Authentication.setDetails(authenticationDetails);
		OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(
				authenticationResult.getClientRegistration(), oauth2Authentication.getName(),
				authenticationResult.getAccessToken(), authenticationResult.getRefreshToken());

		this.authorizedClientRepository.saveAuthorizedClient(authorizedClient, oauth2Authentication, request, response);
		return oauth2Authentication;
	}

4. OAuth2LoginAuthenticationProvider

  • application.yml에 설정해 놓은 scope에 openid 가 없을 경우 수행

  • OAuth2AuthenticationCodeAuthenticationProvider.authenticate 호출

    • 발급 받은 임시코드로 OAuth2AuthenticationCodeAuthenticationProvider 에서 Access-Token 발급 요청
  • OAuth2 Provider 로부터 Access-Token이 정상 발급되면 OAuth2UserService.loadUser 호출

    • 발급 받은 Access-Token 으로 DefaultOAuth2UserService 에서 사용자 정보(UserInfo) 요청
  • 발급 받은 Access-Token 과 응답 받은 사용자 정보(UserInfo)를 취합해서 인증 상태의 Authentication(OAuth2LoginAuthenticationToken) 반환

	@Override
	public Authentication authenticate(Authentication authentication) throws AuthenticationException {
		OAuth2LoginAuthenticationToken loginAuthenticationToken = (OAuth2LoginAuthenticationToken) authentication;
		// Section 3.1.2.1 Authentication Request -
		// https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest scope
		// REQUIRED. OpenID Connect requests MUST contain the "openid" scope value.
		if (loginAuthenticationToken.getAuthorizationExchange()
			.getAuthorizationRequest()
			.getScopes()
			.contains("openid")) {
			// This is an OpenID Connect Authentication Request so return null
			// and let OidcAuthorizationCodeAuthenticationProvider handle it instead
			return null;
		}
		OAuth2AuthorizationCodeAuthenticationToken authorizationCodeAuthenticationToken;
		try {
			authorizationCodeAuthenticationToken = (OAuth2AuthorizationCodeAuthenticationToken) this.authorizationCodeAuthenticationProvider
				.authenticate(
						new OAuth2AuthorizationCodeAuthenticationToken(loginAuthenticationToken.getClientRegistration(),
								loginAuthenticationToken.getAuthorizationExchange()));
		}
		catch (OAuth2AuthorizationException ex) {
			OAuth2Error oauth2Error = ex.getError();
			throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString(), ex);
		}
		OAuth2AccessToken accessToken = authorizationCodeAuthenticationToken.getAccessToken();
		Map<String, Object> additionalParameters = authorizationCodeAuthenticationToken.getAdditionalParameters();
		OAuth2User oauth2User = this.userService.loadUser(new OAuth2UserRequest(
				loginAuthenticationToken.getClientRegistration(), accessToken, additionalParameters));
		Collection<? extends GrantedAuthority> mappedAuthorities = this.authoritiesMapper
			.mapAuthorities(oauth2User.getAuthorities());
		OAuth2LoginAuthenticationToken authenticationResult = new OAuth2LoginAuthenticationToken(
				loginAuthenticationToken.getClientRegistration(), loginAuthenticationToken.getAuthorizationExchange(),
				oauth2User, mappedAuthorities, accessToken, authorizationCodeAuthenticationToken.getRefreshToken());
		authenticationResult.setDetails(loginAuthenticationToken.getDetails());
		return authenticationResult;
	}

5. OAuth2AuthorizationCodeAuthenticationProvider

  • 사용자 로그인 성공 시 발급받은 임시코드를 통해 OAuth2 Provider 에게 Access-Token 요청 하는 Provider
  • OAuth2AccessTokenResponseClient(DefaultAuthorizationCodeTokenResponseClient) 에서 Access-Token 요청 수행
	@Override
	public Authentication authenticate(Authentication authentication) throws AuthenticationException {
		OAuth2AuthorizationCodeAuthenticationToken authorizationCodeAuthentication = (OAuth2AuthorizationCodeAuthenticationToken) authentication;
		OAuth2AuthorizationResponse authorizationResponse = authorizationCodeAuthentication.getAuthorizationExchange()
			.getAuthorizationResponse();
		if (authorizationResponse.statusError()) {
			throw new OAuth2AuthorizationException(authorizationResponse.getError());
		}
		OAuth2AuthorizationRequest authorizationRequest = authorizationCodeAuthentication.getAuthorizationExchange()
			.getAuthorizationRequest();
		if (!authorizationResponse.getState().equals(authorizationRequest.getState())) {
			OAuth2Error oauth2Error = new OAuth2Error(INVALID_STATE_PARAMETER_ERROR_CODE);
			throw new OAuth2AuthorizationException(oauth2Error);
		}
		OAuth2AccessTokenResponse accessTokenResponse = this.accessTokenResponseClient.getTokenResponse(
				new OAuth2AuthorizationCodeGrantRequest(authorizationCodeAuthentication.getClientRegistration(),
						authorizationCodeAuthentication.getAuthorizationExchange()));
		OAuth2AuthorizationCodeAuthenticationToken authenticationResult = new OAuth2AuthorizationCodeAuthenticationToken(
				authorizationCodeAuthentication.getClientRegistration(),
				authorizationCodeAuthentication.getAuthorizationExchange(), accessTokenResponse.getAccessToken(),
				accessTokenResponse.getRefreshToken(), accessTokenResponse.getAdditionalParameters());
		authenticationResult.setDetails(authorizationCodeAuthentication.getDetails());
		return authenticationResult;
	}

6. CustomOAuth2UserService

  • OAuth2UserService 커스텀 구현체
  • DefaultOAuth2UserService.loadUser() 호출해서 Access-Token 으로 사용자 정보(UserInfo)를 얻는다.
  • 각각 다른 OAuth2 Provider 사용자 정보(UserInfo) 를 토대로 공통 사용자 정보를 담는 SocialMember 클래스 생성
  • 생성된 공통 SocialMember 클래스로 DB에 Member 정보 질의, 없으면 Insert
  • DB 질의된 Member 정보를 토대로 OAuth2User, OidcUser 구현체 OAuth2Payload 생성 후 리턴
  @Override
  public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
    ClientRegistration clientRegistration = userRequest.getClientRegistration();
    OAuth2UserService<OAuth2UserRequest, OAuth2User> oAuth2UserService = new DefaultOAuth2UserService();
    OAuth2User oAuth2User = oAuth2UserService.loadUser(userRequest);
    SocialMember socialMember = SocialMember.of(clientRegistration, oAuth2User);

    Optional<MemberDto> findMemberDto = service.findByUserIdAndSocialType(socialMember.getEmail(), socialMember.getSocialType());
    if (findMemberDto.isEmpty()) {
      MemberJoinRequest memberJoinRequest = MemberJoinRequest.of(socialMember);
      //save OAuth2 Member
      MemberDto savedDto = service.save(mapper.toDto(memberJoinRequest, passwordEncoder));
      findMemberDto = Optional.of(savedDto);
    }

    return new OAuth2Payload(socialMember, Payload.of(MemberDetails.of(findMemberDto.get())));
  }

7. SocialMember

  • 각기 다른 OAuth2 Provider 사용자 정보(UserInfo) 클래스를 추상화한 클래스
@Getter
public abstract class SocialMember {

  private final SocialType socialType;
  protected final OAuth2User oAuth2User;

  protected SocialMember(SocialType socialType, OAuth2User oAuth2User) {
    this.socialType = socialType;
    this.oAuth2User = oAuth2User;
  }

  public abstract String getOAuthKey();

  public abstract String getUsername();

  public String getEmail() {
    return oAuth2User.getAttribute("email");
  }

  public static SocialMember of(ClientRegistration clientRegistration, OAuth2User oAuth2User) {
    SocialType socialType = SocialType.findByRegistrationId(clientRegistration.getRegistrationId());
    switch (socialType) {
      case KAKAO -> {
        return new KakaoMember(socialType, oAuth2User);
      }
      case NAVER -> {
        return new NaverMember(socialType, oAuth2User);
      }
      case GOOGLE -> {
        return new GoogleMember(socialType, oAuth2User);
      }
      case KEYCLOAK -> {
        return new KeycloakMember(socialType, oAuth2User);
      }
      case GITHUB -> {
        return null;
      }
    }
    return null;
  }
}

8. DefaultOAuth2UserService

  • Access-Token 으로 사용자 정보(UserInfo)를 요청하는 Spring Security 기본 제공 클래스
  • 응답 받은 사용자 정보(UserInfo) 를 토대로 OAuth2User(DefaultOAuth2User) 반환
	@Override
	public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
		Assert.notNull(userRequest, "userRequest cannot be null");
		if (!StringUtils
			.hasText(userRequest.getClientRegistration().getProviderDetails().getUserInfoEndpoint().getUri())) {
			OAuth2Error oauth2Error = new OAuth2Error(MISSING_USER_INFO_URI_ERROR_CODE,
					"Missing required UserInfo Uri in UserInfoEndpoint for Client Registration: "
							+ userRequest.getClientRegistration().getRegistrationId(),
					null);
			throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
		}
		String userNameAttributeName = userRequest.getClientRegistration()
			.getProviderDetails()
			.getUserInfoEndpoint()
			.getUserNameAttributeName();
		if (!StringUtils.hasText(userNameAttributeName)) {
			OAuth2Error oauth2Error = new OAuth2Error(MISSING_USER_NAME_ATTRIBUTE_ERROR_CODE,
					"Missing required \"user name\" attribute name in UserInfoEndpoint for Client Registration: "
							+ userRequest.getClientRegistration().getRegistrationId(),
					null);
			throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
		}
		RequestEntity<?> request = this.requestEntityConverter.convert(userRequest);
		ResponseEntity<Map<String, Object>> response = getResponse(userRequest, request);
		Map<String, Object> userAttributes = response.getBody();
		Set<GrantedAuthority> authorities = new LinkedHashSet<>();
		authorities.add(new OAuth2UserAuthority(userAttributes));
		OAuth2AccessToken token = userRequest.getAccessToken();
		for (String authority : token.getScopes()) {
			authorities.add(new SimpleGrantedAuthority("SCOPE_" + authority));
		}
		return new DefaultOAuth2User(authorities, userAttributes, userNameAttributeName);
	}

9. LoginSuccessHandler

  • 어플리케이션 로그인과 로직 동일
    • 응집도 높인다.
  • 단, OAuth2 로그인 이면
    • 생성된 Access-Token, Refresh-Token 쿠키 생성
    • 302 Redirect 처리
  @Override
  public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
      throws IOException, ServletException {
    Payload payload = TokenUtil.getPayload();
    String accessToken = jwtProvider.createToken(payload);
    String refreshToken = jwtProvider.refreshToken(payload.getRedisKey());
    Jwt jwt = new Jwt(accessToken, refreshToken);

    redisService.accessTokenSave(payload.getRedisKey(), jwt.getAccessToken());
    redisService.refreshTokenSave(payload.getRedisKey(), jwt.getRefreshToken());

    int refreshTokenMaxAge = (int) jwtProvider.getRefreshExpirationTime() / 1000;

    Cookie refreshTokenCookie = CookieUtil.createCookie(
        jwtProvider.getRefreshTokenHeader(),
        URLEncoder.encode(refreshToken, StandardCharsets.UTF_8),
        refreshTokenMaxAge,
        true,
        false,
        "/"
    );

    CookieUtil.addCookie(response, refreshTokenCookie);

    if (TokenUtil.isInitSocialLogin()) {
      int accessTokenMaxAge = (int) jwtProvider.getExpirationTime() / 1000;

      Cookie accessTokenCookie = CookieUtil.createCookie(
          jwtProvider.getAccessTokenHeader(),
          URLEncoder.encode(jwtProvider.getTokenPrefix() + accessToken, StandardCharsets.UTF_8),
          accessTokenMaxAge,
          false,
          false,
          "/"
      );

      Cookie idCookie = CookieUtil.createCookie(
          "id",
          String.valueOf(payload.getId()),
          accessTokenMaxAge,
          false,
          false,
          "/"
      );

      CookieUtil.addCookie(response, accessTokenCookie, idCookie);
      response.sendRedirect("http://localhost:8081/oauth2-signin-success");
      return;
    }

    response.setStatus(HttpStatus.OK.value());
    response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);

    response.setHeader(jwtProvider.getAccessTokenHeader(), jwtProvider.getTokenPrefix() + jwt.getAccessToken());
    response.setHeader(jwtProvider.getRefreshTokenHeader(), jwtProvider.getTokenPrefix() + jwt.getRefreshToken());
    LoginResponse loginResponse = new LoginResponse(jwt, payload.getId());
    PrintWriter writer = response.getWriter();
    writer.println(new ObjectMapper().writeValueAsString(loginResponse));
    writer.flush();
    writer.close();
  }

10. OAuth2SignInSuccess.jsx

  • OAuth2 로그인 성공 후 Redirect 페이지
  • Access-Token, memberId Cookie 값 read 후 삭제
    • Access-Token 을 파라미터로 던져도 되지만... 파라미터보단 쿠키로 받은 후 바로 삭제하는 방법을 택함
const OAuth2SignInSuccess = () => {
  const {loginSuccess, setLoginSuccess, setAuthChecked} = useContext(
      DiaryStateContext);
  const nav = useNavigate();

  useEffect(() => {
    const accessToken = getCookie("Authorization");
    const memberId = getCookie("id");
    if (accessToken && memberId) {
      axiosInstance.defaults.headers.common['Authorization'] = accessToken;
      localStorage.setItem("id", memberId);
      removeCookie("Authorization");
      removeCookie("id");
      setLoginSuccess(true);
      setAuthChecked(true);
      nav("/", {replace: true});
    } else {
      nav("/signin", {replace: true})
    }
    return;
  }, [loginSuccess]);
}

Oidc 로그인 프로세스

Oidc 로그인 프로세스

OAuth2LoginAuthenticationFilter 과정까지는 OAuth2 로그인 프로세스와 동일하다.

❗️ OAuth2 로그인 프로세스와 Oidc 로그인 프로세스 차이점

  • scope에 openid 유무에 따라 인증 위임 클래스가 다르고, OAuth2 Provider로 부터 Access-Token 발급 요청 시 Id-Token 발급 유무가 다르다.
    • Id-Token 에는 사용자의 기본 정보가 제공된다.
  1. OAuth2 Provider 에 Access-Token 발급 요청 시 OAuth2 Provider에 접근 가능한 scope를 리턴해주는데 이 scope에 사용자 정보(PROFILE, EMAIL, ADDRESS, PHONE) 요청 관련 값이 존재 유무에 따라 사용자 정보 요청을 처리한다.

1. OidcAuthenticationCodeAuthenticationProvider

  • application.yml에 설정해 놓은 scope에 openid 가 있을 경우, OAuth2LoginAuthenticationProvider 가 아닌 해당 클래스의 authenticate 수행
  • 발급 받은 임시코드로 Access-Token, Id-Token 발급 요청 직접 수행
  • Access-Token, Id-Token 정상 발급 되면 OAuth2UserService.loadUser() 호출
    • scope 에 PROFILE, EMAIL, ADDRESS, PHONE 정보가 존재하면
      • 발급 받은 Access-Token 으로 OidcUserService 에서 사용자 정보(UserInfo) 요청
    • scope 에 PROFILE, EMAIL, ADDRESS, PHONE 정보가 없으면
      • 사용자 정보(UserInfo) 호출 안 함
        => OidcUser 에서 OidcUserInfo는 null
      • OidcIdToken 에 사용자 정보(UserInfo)가 어느정도 담겨 있음
  • 발급 받은 Access-Token, Id-Token, 사용자 정보(UserInfo) 를 취합해서 인증 상태의 Authentication(OAuth2LoginAuthenticationToken) 반환
	@Override
	public Authentication authenticate(Authentication authentication) throws AuthenticationException {
		OAuth2LoginAuthenticationToken authorizationCodeAuthentication = (OAuth2LoginAuthenticationToken) authentication;
		// Section 3.1.2.1 Authentication Request -
		// https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest
		// scope
		// REQUIRED. OpenID Connect requests MUST contain the "openid" scope value.
		if (!authorizationCodeAuthentication.getAuthorizationExchange()
			.getAuthorizationRequest()
			.getScopes()
			.contains(OidcScopes.OPENID)) {
			// This is NOT an OpenID Connect Authentication Request so return null
			// and let OAuth2LoginAuthenticationProvider handle it instead
			return null;
		}
		OAuth2AuthorizationRequest authorizationRequest = authorizationCodeAuthentication.getAuthorizationExchange()
			.getAuthorizationRequest();
		OAuth2AuthorizationResponse authorizationResponse = authorizationCodeAuthentication.getAuthorizationExchange()
			.getAuthorizationResponse();
		if (authorizationResponse.statusError()) {
			throw new OAuth2AuthenticationException(authorizationResponse.getError(),
					authorizationResponse.getError().toString());
		}
		if (!authorizationResponse.getState().equals(authorizationRequest.getState())) {
			OAuth2Error oauth2Error = new OAuth2Error(INVALID_STATE_PARAMETER_ERROR_CODE);
			throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
		}
		OAuth2AccessTokenResponse accessTokenResponse = getResponse(authorizationCodeAuthentication);
		ClientRegistration clientRegistration = authorizationCodeAuthentication.getClientRegistration();
		Map<String, Object> additionalParameters = accessTokenResponse.getAdditionalParameters();
		if (!additionalParameters.containsKey(OidcParameterNames.ID_TOKEN)) {
			OAuth2Error invalidIdTokenError = new OAuth2Error(INVALID_ID_TOKEN_ERROR_CODE,
					"Missing (required) ID Token in Token Response for Client Registration: "
							+ clientRegistration.getRegistrationId(),
					null);
			throw new OAuth2AuthenticationException(invalidIdTokenError, invalidIdTokenError.toString());
		}
		OidcIdToken idToken = createOidcToken(clientRegistration, accessTokenResponse);
		validateNonce(authorizationRequest, idToken);
		OidcUser oidcUser = this.userService.loadUser(new OidcUserRequest(clientRegistration,
				accessTokenResponse.getAccessToken(), idToken, additionalParameters));
		Collection<? extends GrantedAuthority> mappedAuthorities = this.authoritiesMapper
			.mapAuthorities(oidcUser.getAuthorities());
		OAuth2LoginAuthenticationToken authenticationResult = new OAuth2LoginAuthenticationToken(
				authorizationCodeAuthentication.getClientRegistration(),
				authorizationCodeAuthentication.getAuthorizationExchange(), oidcUser, mappedAuthorities,
				accessTokenResponse.getAccessToken(), accessTokenResponse.getRefreshToken());
		authenticationResult.setDetails(authorizationCodeAuthentication.getDetails());
		return authenticationResult;
	}

2. CustomOidcUserService

  • OAuth2UserService 의 커스텀 구현체
  • OidcUserService.loadUser() 호출해서 Scope 유효성 검증 후 Access-Token 으로 사용자 정보(UserInfo)를 응답 받아 OidcUser(DefaultOidcUser) 를 얻는다.
  • 각각 다른 OAuth2 Provider 사용자 정보(UserInfo) 를 토대로 공통 사용자 정보를 담는 SocialMember 클래스 생성
  • 생성된 공통 SocialMember 클래스로 DB에 Member 정보 질의, 없으면 Insert
  • DB 질의된 Member 정보를 토대로 OAuth2User, OidcUser 구현체 OAuth2Payload 생성 후 리턴
  @Override
  public OidcUser loadUser(OidcUserRequest userRequest) throws OAuth2AuthenticationException {
    ClientRegistration clientRegistration = userRequest.getClientRegistration();
    OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService = new OidcUserService();
    OidcUser oidcUser = oidcUserService.loadUser(userRequest);
    SocialMember socialMember = SocialMember.of(clientRegistration, oidcUser);

    Optional<MemberDto> findMemberDto = service.findByUserIdAndSocialType(socialMember.getEmail(), socialMember.getSocialType());
    if (findMemberDto.isEmpty()) {
      MemberJoinRequest memberJoinRequest = MemberJoinRequest.of(socialMember);
      //save OAuth2 Member
      MemberDto savedDto = service.save(mapper.toDto(memberJoinRequest, passwordEncoder));
      findMemberDto = Optional.of(savedDto);
    }

    return new OAuth2Payload(socialMember, Payload.of(MemberDetails.of(findMemberDto.get())));
  }

이후는 OAuth2 로그인 프로세스와 동일함.

★ GitHub URL

front-end : https://github.com/onlydev7777/emotion-diary-react
back-end : https://github.com/onlydev7777/emotion-diary-monolithic

profile
https://github.com/onlydev7777

0개의 댓글