-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: OAuth(Kakao) Service를 구현한다. (#15)
* feat: RestTemplate Config를 추가한다. * feat: Kakao 서버에 User Data를 요청하는 Handler를 추가한다. * feat: KakaoHandler를 호출하는 OAuthService를 추가한다. * feat: 요청/응답에 필요한 dto 추가 * feat: 신규 ErrorCode를 추가한다. * feat: 공통 설정을 application.yml로 분리
- Loading branch information
Showing
13 changed files
with
288 additions
and
22 deletions.
There are no files selected for viewing
36 changes: 36 additions & 0 deletions
36
src/main/java/com/dnd/accompany/domain/auth/oauth/dto/KakaoUserData.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package com.dnd.accompany.domain.auth.oauth.dto; | ||
|
||
import com.fasterxml.jackson.annotation.JsonProperty; | ||
|
||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Getter | ||
@NoArgsConstructor | ||
public class KakaoUserData { | ||
@JsonProperty("id") | ||
private Long id; | ||
@JsonProperty("kakao_account") | ||
private KakaoAccount kakaoAccount; | ||
|
||
@Getter | ||
@NoArgsConstructor | ||
static class KakaoAccount { | ||
private String email; | ||
private KakaoProfile profile; | ||
} | ||
|
||
@Getter | ||
@NoArgsConstructor | ||
static class KakaoProfile { | ||
private String nickname; | ||
} | ||
|
||
public String getEmail() { | ||
return kakaoAccount.getEmail(); | ||
} | ||
|
||
public String getNickname() { | ||
return kakaoAccount.getProfile().getNickname(); | ||
} | ||
} |
9 changes: 9 additions & 0 deletions
9
src/main/java/com/dnd/accompany/domain/auth/oauth/dto/LoginRequest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package com.dnd.accompany.domain.auth.oauth.dto; | ||
|
||
import com.dnd.accompany.domain.auth.oauth.service.OAuthProvider; | ||
|
||
public record LoginRequest( | ||
OAuthProvider provider, | ||
String accessToken | ||
) { | ||
} |
10 changes: 10 additions & 0 deletions
10
src/main/java/com/dnd/accompany/domain/auth/oauth/dto/OAuthUserDataRequest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package com.dnd.accompany.domain.auth.oauth.dto; | ||
|
||
import lombok.AllArgsConstructor; | ||
import lombok.Getter; | ||
|
||
@Getter | ||
@AllArgsConstructor | ||
public class OAuthUserDataRequest { | ||
private String accessToken; | ||
} |
17 changes: 17 additions & 0 deletions
17
src/main/java/com/dnd/accompany/domain/auth/oauth/dto/OAuthUserDataResponse.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package com.dnd.accompany.domain.auth.oauth.dto; | ||
|
||
import lombok.AllArgsConstructor; | ||
import lombok.Builder; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Getter | ||
@Builder | ||
@NoArgsConstructor | ||
@AllArgsConstructor | ||
public class OAuthUserDataResponse { | ||
private String provider; | ||
private String oauthId; | ||
private String email; | ||
private String nickname; | ||
} |
10 changes: 10 additions & 0 deletions
10
src/main/java/com/dnd/accompany/domain/auth/oauth/exception/HttpClientException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package com.dnd.accompany.domain.auth.oauth.exception; | ||
|
||
import com.dnd.accompany.global.common.exception.BusinessException; | ||
import com.dnd.accompany.global.common.response.ErrorCode; | ||
|
||
public class HttpClientException extends BusinessException { | ||
public HttpClientException(ErrorCode errorCode) { | ||
super(errorCode); | ||
} | ||
} |
76 changes: 76 additions & 0 deletions
76
src/main/java/com/dnd/accompany/domain/auth/oauth/handler/KakaoService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package com.dnd.accompany.domain.auth.oauth.handler; | ||
|
||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.http.HttpEntity; | ||
import org.springframework.http.HttpHeaders; | ||
import org.springframework.http.HttpMethod; | ||
import org.springframework.http.MediaType; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.stereotype.Component; | ||
import org.springframework.web.client.RestClientException; | ||
import org.springframework.web.client.RestClientResponseException; | ||
import org.springframework.web.client.RestTemplate; | ||
|
||
import com.dnd.accompany.domain.auth.oauth.dto.KakaoUserData; | ||
import com.dnd.accompany.domain.auth.oauth.dto.OAuthUserDataRequest; | ||
import com.dnd.accompany.domain.auth.oauth.dto.OAuthUserDataResponse; | ||
import com.dnd.accompany.domain.auth.oauth.exception.HttpClientException; | ||
import com.dnd.accompany.domain.auth.oauth.service.OAuthProvider; | ||
import com.dnd.accompany.global.common.response.ErrorCode; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
|
||
@Slf4j | ||
@Component | ||
@RequiredArgsConstructor | ||
public class KakaoService implements OAuthAuthenticationHandler { | ||
|
||
private final RestTemplate restTemplate; | ||
|
||
@Value("${spring.oauth2.kakao.host}") | ||
private String host; | ||
|
||
@Override | ||
public OAuthProvider getAuthProvider() { | ||
return OAuthProvider.KAKAO; | ||
} | ||
|
||
@Override | ||
public OAuthUserDataResponse getOAuthUserData(OAuthUserDataRequest request) { | ||
String url = host + "/v2/user/me"; | ||
|
||
HttpHeaders httpHeaders = new HttpHeaders(); | ||
httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED); | ||
httpHeaders.add("Authorization", "Bearer " + request.getAccessToken()); | ||
|
||
HttpEntity<?> httpRequest = new HttpEntity<>(null, httpHeaders); | ||
|
||
try { | ||
ResponseEntity<KakaoUserData> response = restTemplate.exchange( | ||
url, | ||
HttpMethod.GET, | ||
httpRequest, | ||
KakaoUserData.class | ||
); | ||
assert response.getBody() != null; | ||
|
||
KakaoUserData userData = response.getBody(); | ||
return OAuthUserDataResponse.builder() | ||
.provider(getAuthProvider().toString()) | ||
.oauthId(userData.getId().toString()) | ||
.email(userData.getEmail()) | ||
.nickname(userData.getNickname()) | ||
.build(); | ||
|
||
} catch (RestClientException e) { | ||
log.warn("[KakaoService] failed to get OAuth User Data = {}", request.getAccessToken()); | ||
|
||
if (e instanceof RestClientResponseException) { | ||
throw new HttpClientException(ErrorCode.INVALID_OAUTH_TOKEN); | ||
} | ||
|
||
throw new HttpClientException(ErrorCode.HTTP_CLIENT_REQUEST_FAILED); | ||
} | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
src/main/java/com/dnd/accompany/domain/auth/oauth/handler/OAuthAuthenticationHandler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package com.dnd.accompany.domain.auth.oauth.handler; | ||
|
||
import com.dnd.accompany.domain.auth.oauth.dto.OAuthUserDataRequest; | ||
import com.dnd.accompany.domain.auth.oauth.dto.OAuthUserDataResponse; | ||
import com.dnd.accompany.domain.auth.oauth.service.OAuthProvider; | ||
|
||
public interface OAuthAuthenticationHandler { | ||
OAuthProvider getAuthProvider(); | ||
|
||
OAuthUserDataResponse getOAuthUserData(OAuthUserDataRequest request); | ||
} |
25 changes: 25 additions & 0 deletions
25
src/main/java/com/dnd/accompany/domain/auth/oauth/service/OAuthProvider.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package com.dnd.accompany.domain.auth.oauth.service; | ||
|
||
import java.util.Arrays; | ||
|
||
import com.dnd.accompany.global.common.exception.NotFoundException; | ||
import com.dnd.accompany.global.common.response.ErrorCode; | ||
|
||
import lombok.Getter; | ||
import lombok.RequiredArgsConstructor; | ||
|
||
@Getter | ||
@RequiredArgsConstructor | ||
public enum OAuthProvider { | ||
|
||
KAKAO("KAKAO"); | ||
|
||
private final String name; | ||
|
||
public static OAuthProvider get(OAuthProvider oAuthProvider) { | ||
return Arrays.stream(OAuthProvider.values()) | ||
.filter(provider -> provider.equals(oAuthProvider)) | ||
.findAny() | ||
.orElseThrow(() -> new NotFoundException(ErrorCode.INVALID_PROVIDER)); | ||
} | ||
} |
41 changes: 41 additions & 0 deletions
41
src/main/java/com/dnd/accompany/domain/auth/oauth/service/OAuthService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package com.dnd.accompany.domain.auth.oauth.service; | ||
|
||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.function.Function; | ||
import java.util.stream.Collectors; | ||
|
||
import org.springframework.stereotype.Service; | ||
|
||
import com.dnd.accompany.domain.auth.oauth.dto.LoginRequest; | ||
import com.dnd.accompany.domain.auth.oauth.dto.OAuthUserDataRequest; | ||
import com.dnd.accompany.domain.auth.oauth.dto.OAuthUserDataResponse; | ||
import com.dnd.accompany.domain.auth.oauth.handler.OAuthAuthenticationHandler; | ||
|
||
@Service | ||
public class OAuthService { | ||
|
||
private final Map<OAuthProvider, OAuthAuthenticationHandler> oAuthAuthenticationHandlers; | ||
|
||
public OAuthService(List<OAuthAuthenticationHandler> oAuthAuthenticationHandlers) { | ||
this.oAuthAuthenticationHandlers = oAuthAuthenticationHandlers.stream().collect( | ||
Collectors.toConcurrentMap(OAuthAuthenticationHandler::getAuthProvider, Function.identity()) | ||
); | ||
} | ||
|
||
public OAuthUserDataResponse login(LoginRequest loginRequest) { | ||
OAuthProvider oAuthProvider = OAuthProvider.get(loginRequest.provider()); | ||
|
||
OAuthAuthenticationHandler oAuthHandler = this.oAuthAuthenticationHandlers.get(oAuthProvider); | ||
|
||
OAuthUserDataRequest request = new OAuthUserDataRequest( | ||
loginRequest.accessToken() | ||
); | ||
|
||
return oAuthHandler.getOAuthUserData(request); | ||
} | ||
|
||
public void revoke() { | ||
// 회원 탈퇴 구현 시 추가합니다. | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
22 changes: 22 additions & 0 deletions
22
src/main/java/com/dnd/accompany/global/config/resttemplate/RestTemplateConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package com.dnd.accompany.global.config.resttemplate; | ||
|
||
import java.time.Duration; | ||
|
||
import org.springframework.boot.web.client.RestTemplateBuilder; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.context.annotation.Primary; | ||
import org.springframework.web.client.RestTemplate; | ||
|
||
@Configuration | ||
public class RestTemplateConfig { | ||
|
||
@Primary | ||
@Bean(name = "defaultClient") | ||
public RestTemplate defaultRestTemplate(RestTemplateBuilder builder) { | ||
return builder | ||
.setConnectTimeout(Duration.ofSeconds(3)) | ||
.setReadTimeout(Duration.ofSeconds(5)) | ||
.build(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
server: | ||
port: 8080 | ||
shutdown: graceful | ||
|
||
spring: | ||
jpa: | ||
database-platform: org.hibernate.dialect.MySQLDialect | ||
open-in-view: false | ||
show-sql: true | ||
properties: | ||
hibernate: | ||
format_sql: true | ||
hbm2ddl.auto: update | ||
oauth2: | ||
kakao: | ||
host: https://kapi.kakao.com | ||
|
||
management: | ||
endpoints: | ||
web: | ||
exposure: | ||
include: "*" | ||
exclude: env, beans |