-
Notifications
You must be signed in to change notification settings - Fork 0
deploy: 휴면 스케줄러, GitHub OAuth, 예외 처리 리팩토링, 테스트 코드 dev-deploy 반영 #35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
66467c4
feat: 휴면 전환, 계정 하드 삭제 스케쥴러 구현
Jungeunsun565 4dfa507
feat: github oauth 추가
Jungeunsun565 1becaf8
fix: github oauth로 MyPageServiceImpl 수정
Jungeunsun565 92e5d35
refactor: Service 계층 조회 메서드에 readOnly 트랜잭션 적용
Jungeunsun565 eb3d3e4
fix: 불필요한 이메일 주소 제거 및 FeignClient 어노테이션 수정
Jungeunsun565 bb9c216
Merge pull request #27 from nhnacademy-aiot3-insighton/feature/auth
Jungeunsun565 41c57a4
feat: BusinessException 기반 전역 예외 처리기 추가
Jungeunsun565 a52c55b
refactor: 컨트롤러 응답에서 ApiResponse 제거, DTO 직접 반환
Jungeunsun565 a0070af
fix: Feign Circuit Breaker ID의 하이픈 제거 방지 설정 추가
Jungeunsun565 eb4fbb6
Merge pull request #29 from nhnacademy-aiot3-insighton/feature/auth
Jungeunsun565 ede8d8f
refactor: HeaderAuthenticationFilter X-User-Role 헤더 사용
Jungeunsun565 8a4dbed
Merge pull request #30 from nhnacademy-aiot3-insighton/refactor/heade…
Jungeunsun565 2338e5f
test: User, UserCredential, UserRole, Oauth 엔티티 테스트 작성
Jungeunsun565 04bbc4b
Merge pull request #32 from nhnacademy-aiot3-insighton/test/entity
Jungeunsun565 2a76b47
test: UserRepository, UserRoleRepository, UserCredentialRepository, O…
Jungeunsun565 3f2a170
Merge pull request #34 from nhnacademy-aiot3-insighton/test/repository
Jungeunsun565 284b984
fix: 분산 락을 Redisson으로 교체해 스케줄러 중복 실행 방지
Jungeunsun565 c341f66
fix: OAuth 로그인 시 기존 사용자 lastLoginAt 미갱신 문제 수정
Jungeunsun565 5ec222e
fix: Resilience4j 설정이 적용되지 않던 문제 수정
Jungeunsun565 bec00e5
fix: rebase 후 테스트 실패 수정 (Redisson AUTH, lastLoginAt)
Jungeunsun565 8e216e2
fix: OAuth 이메일 검증 및 중복 처리 강화
Jungeunsun565 6aef4f3
fix: Dockerfile 수정
Jungeunsun565 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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 hidden or 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 hidden or 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
13 changes: 13 additions & 0 deletions
13
src/main/java/com/nhnacademy/insightonauth/client/CoreClient.java
This file contains hidden or 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,13 @@ | ||
| package com.nhnacademy.insightonauth.client; | ||
|
|
||
| import com.nhnacademy.insightonauth.dto.core.ManagerGroupExistsResponse; | ||
| import org.springframework.cloud.openfeign.FeignClient; | ||
| import org.springframework.web.bind.annotation.GetMapping; | ||
| import org.springframework.web.bind.annotation.PathVariable; | ||
|
|
||
| @FeignClient(name = "insighton-core") | ||
| public interface CoreClient { | ||
|
|
||
| @GetMapping("/internal/v1/users/{userId}/manager-groups/exists") | ||
| ManagerGroupExistsResponse existsManagerGroup(@PathVariable Long userId); | ||
| } |
61 changes: 2 additions & 59 deletions
61
src/main/java/com/nhnacademy/insightonauth/client/OauthClient.java
This file contains hidden or 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 |
|---|---|---|
| @@ -1,65 +1,8 @@ | ||
| package com.nhnacademy.insightonauth.client; | ||
|
|
||
| import com.nhnacademy.insightonauth.dto.oauth.OauthUserInfo; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.beans.factory.annotation.Value; | ||
| import org.springframework.http.MediaType; | ||
| import org.springframework.stereotype.Component; | ||
| import org.springframework.util.LinkedMultiValueMap; | ||
| import org.springframework.util.MultiValueMap; | ||
| import org.springframework.web.client.RestClient; | ||
|
|
||
| import java.util.Map; | ||
| public interface OauthClient { | ||
|
|
||
| @Component | ||
| @RequiredArgsConstructor | ||
| public class OauthClient { | ||
|
|
||
| @Value("${oauth.google.client-id}") | ||
| private String clientId; | ||
|
|
||
| @Value("${oauth.google.client-secret}") | ||
| private String clientSecret; | ||
|
|
||
| @Value("${oauth.google.redirect-uri}") | ||
| private String redirectUri; | ||
|
|
||
| private final RestClient restClient = RestClient.create(); | ||
|
|
||
| public OauthUserInfo getUserInfo(String provider, String code) { | ||
| String accessToken = requestAccessToken(code); | ||
| return requestUserInfo(accessToken); | ||
| } | ||
|
|
||
| private String requestAccessToken(String code) { | ||
| MultiValueMap<String, String> body = new LinkedMultiValueMap<>(); | ||
| body.add("code", code); | ||
| body.add("client_id", clientId); | ||
| body.add("client_secret", clientSecret); | ||
| body.add("redirect_uri", redirectUri); | ||
| body.add("grant_type", "authorization_code"); | ||
|
|
||
| Map<String, Object> response = restClient.post() | ||
| .uri("https://oauth2.googleapis.com/token") | ||
| .contentType(MediaType.APPLICATION_FORM_URLENCODED) | ||
| .body(body) | ||
| .retrieve() | ||
| .body(Map.class); | ||
|
|
||
| return (String) response.get("access_token"); | ||
| } | ||
|
|
||
| private OauthUserInfo requestUserInfo(String accessToken) { | ||
| Map<String, Object> userInfo = restClient.get() | ||
| .uri("https://www.googleapis.com/oauth2/v3/userinfo") | ||
| .header("Authorization", "Bearer " + accessToken) | ||
| .retrieve() | ||
| .body(Map.class); | ||
|
|
||
| return new OauthUserInfo( | ||
| (String) userInfo.get("email"), | ||
| (String) userInfo.get("name"), | ||
| (String) userInfo.get("sub") | ||
| ); | ||
| } | ||
| OauthUserInfo getUserInfo(String code); | ||
| } |
22 changes: 22 additions & 0 deletions
22
src/main/java/com/nhnacademy/insightonauth/client/OauthClientResolver.java
This file contains hidden or 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.nhnacademy.insightonauth.client; | ||
|
|
||
| import com.nhnacademy.insightonauth.exception.UnsupportedOAuthProviderException; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.stereotype.Component; | ||
|
|
||
| import java.util.Map; | ||
|
|
||
| @Component | ||
| @RequiredArgsConstructor | ||
| public class OauthClientResolver { | ||
| // 스프링이 bean 객체를 가져다줌 | ||
| private final Map<String, OauthClient> clients; | ||
|
|
||
| public OauthClient resolve(String provider) { | ||
| OauthClient client = clients.get(provider + "OauthClient"); | ||
| if (client == null) { | ||
| throw new UnsupportedOAuthProviderException(provider); | ||
| } | ||
| return client; | ||
| } | ||
| } |
103 changes: 103 additions & 0 deletions
103
src/main/java/com/nhnacademy/insightonauth/client/impl/GithubOauthClient.java
This file contains hidden or 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,103 @@ | ||
| package com.nhnacademy.insightonauth.client.impl; | ||
|
|
||
| import com.nhnacademy.insightonauth.client.OauthClient; | ||
| import com.nhnacademy.insightonauth.dto.oauth.OauthUserInfo; | ||
| import com.nhnacademy.insightonauth.exception.EmailNotFoundException; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.beans.factory.annotation.Value; | ||
| import org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder; | ||
| import org.springframework.boot.http.client.ClientHttpRequestFactorySettings; | ||
| import org.springframework.http.MediaType; | ||
| import org.springframework.stereotype.Component; | ||
| import org.springframework.util.LinkedMultiValueMap; | ||
| import org.springframework.util.MultiValueMap; | ||
| import org.springframework.web.client.RestClient; | ||
|
|
||
| import java.time.Duration; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
|
|
||
| @Component("githubOauthClient") | ||
| @RequiredArgsConstructor | ||
| public class GithubOauthClient implements OauthClient { | ||
|
|
||
| @Value("${oauth.github.client-id}") | ||
| private String clientId; | ||
|
|
||
| @Value("${oauth.github.client-secret}") | ||
| private String clientSecret; | ||
|
|
||
| @Value("${oauth.redirect-uri}") | ||
| private String redirectUri; | ||
|
|
||
| private final RestClient restClient = RestClient.builder() | ||
| .requestFactory(ClientHttpRequestFactoryBuilder.detect() | ||
| .build(ClientHttpRequestFactorySettings.defaults() | ||
| .withConnectTimeout(Duration.ofSeconds(3)) | ||
| .withReadTimeout(Duration.ofSeconds(5)))) | ||
| .build(); | ||
|
|
||
| @Override | ||
| public OauthUserInfo getUserInfo(String code) { | ||
| String accessToken = requestAccessToken(code); | ||
| return requestUserInfo(accessToken); | ||
| } | ||
|
|
||
| private String requestAccessToken(String code) { | ||
| MultiValueMap<String, String> body = new LinkedMultiValueMap<>(); | ||
| body.add("code", code); | ||
| body.add("client_id", clientId); | ||
| body.add("client_secret", clientSecret); | ||
| body.add("redirect_uri", redirectUri); | ||
|
|
||
| Map<String, Object> response = restClient.post() | ||
| .uri("https://github.com/login/oauth/access_token") // GitHub URL로 수정 | ||
| .header("Accept", "application/json") // JSON 응답 요청 (필수) | ||
| .contentType(MediaType.APPLICATION_FORM_URLENCODED) | ||
| .body(body) | ||
| .retrieve() | ||
| .body(Map.class); | ||
|
|
||
| return (String) response.get("access_token"); | ||
| } | ||
|
|
||
| private OauthUserInfo requestUserInfo(String accessToken) { | ||
| Map<String, Object> userInfo = restClient.get() | ||
| .uri("https://api.github.com/user") // GitHub URL로 수정 | ||
| .header("Authorization", "Bearer " + accessToken) | ||
| .retrieve() | ||
| .body(Map.class); | ||
|
|
||
| String email = requestPrimaryEmail(accessToken); | ||
|
|
||
| String name = (String) userInfo.get("name"); | ||
| if (name == null || name.isBlank()) { | ||
| name = (String) userInfo.get("login"); // name이 없으면 login(아이디)으로 대체 | ||
| } | ||
|
|
||
| Object id = userInfo.get("id"); // GitHub은 sub가 아니라 id (숫자) | ||
|
|
||
| return new OauthUserInfo( | ||
| email, | ||
| name, | ||
| String.valueOf(id) | ||
| ); | ||
| } | ||
|
|
||
| // 이메일 열람 불가의 경우 api를 통해서 가져와야함 | ||
| private String requestPrimaryEmail(String accessToken) { | ||
| List<Map<String, Object>> emails = restClient.get() | ||
| .uri("https://api.github.com/user/emails") | ||
| .header("Authorization", "Bearer " + accessToken) | ||
| .retrieve() | ||
| .body(List.class); | ||
|
|
||
| // primary git에서 대표로 지정된 이메일 가져옴, verified 그 중에 인증된거 가져옴 | ||
| return emails.stream() | ||
| .filter(e -> | ||
| Boolean.TRUE.equals(e.get("primary")) && Boolean.TRUE.equals(e.get("verified"))) | ||
| .map(e -> (String) e.get("email")) | ||
| .findFirst() | ||
| .orElseThrow(() -> new EmailNotFoundException("GitHub 계정에서 이메일을 찾을 수 없습니다.")); | ||
| } | ||
| } | ||
76 changes: 76 additions & 0 deletions
76
src/main/java/com/nhnacademy/insightonauth/client/impl/GoogleOauthClient.java
This file contains hidden or 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.nhnacademy.insightonauth.client.impl; | ||
|
|
||
| import com.nhnacademy.insightonauth.client.OauthClient; | ||
| import com.nhnacademy.insightonauth.dto.oauth.OauthUserInfo; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.beans.factory.annotation.Value; | ||
| import org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder; | ||
| import org.springframework.boot.http.client.ClientHttpRequestFactorySettings; | ||
| import org.springframework.http.MediaType; | ||
| import org.springframework.stereotype.Component; | ||
| import org.springframework.util.LinkedMultiValueMap; | ||
| import org.springframework.util.MultiValueMap; | ||
| import org.springframework.web.client.RestClient; | ||
|
|
||
| import java.time.Duration; | ||
| import java.util.Map; | ||
|
|
||
| @Component("googleOauthClient") | ||
| @RequiredArgsConstructor | ||
| public class GoogleOauthClient implements OauthClient { | ||
|
|
||
| @Value("${oauth.google.client-id}") | ||
| private String clientId; | ||
|
|
||
| @Value("${oauth.google.client-secret}") | ||
| private String clientSecret; | ||
|
|
||
| @Value("${oauth.redirect-uri}") | ||
| private String redirectUri; | ||
|
|
||
| private final RestClient restClient = RestClient.builder() | ||
| .requestFactory(ClientHttpRequestFactoryBuilder.detect() | ||
| .build(ClientHttpRequestFactorySettings.defaults() | ||
| .withConnectTimeout(Duration.ofSeconds(3)) | ||
| .withReadTimeout(Duration.ofSeconds(5)))) | ||
| .build(); | ||
|
|
||
| @Override | ||
| public OauthUserInfo getUserInfo(String code) { | ||
| String accessToken = requestAccessToken(code); | ||
| return requestUserInfo(accessToken); | ||
| } | ||
|
|
||
| private String requestAccessToken(String code) { | ||
| // FormHttpMessageConverter | ||
| MultiValueMap<String, String> body = new LinkedMultiValueMap<>(); | ||
| body.add("code", code); | ||
| body.add("client_id", clientId); | ||
| body.add("client_secret", clientSecret); | ||
| body.add("redirect_uri", redirectUri); | ||
| body.add("grant_type", "authorization_code"); | ||
|
|
||
| Map<String, Object> response = restClient.post() | ||
| .uri("https://oauth2.googleapis.com/token") | ||
| .contentType(MediaType.APPLICATION_FORM_URLENCODED) | ||
| .body(body) | ||
| .retrieve() | ||
| .body(Map.class); | ||
|
|
||
| return (String) response.get("access_token"); | ||
| } | ||
|
|
||
| private OauthUserInfo requestUserInfo(String accessToken) { | ||
| Map<String, Object> userInfo = restClient.get() | ||
| .uri("https://www.googleapis.com/oauth2/v3/userinfo") | ||
| .header("Authorization", "Bearer " + accessToken) | ||
| .retrieve() | ||
| .body(Map.class); | ||
|
|
||
| return new OauthUserInfo( | ||
| (String) userInfo.get("email"), | ||
| (String) userInfo.get("name"), | ||
| (String) userInfo.get("sub") | ||
| ); | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.