Skip to content

Commit

Permalink
[BE] issue372: Github Token 받아오는 과정을 트랜잭션에서 제외 (#373)
Browse files Browse the repository at this point in the history
* feat: 트랜잭션 분리

* feat: public 메소드로 변경

* refactor: OAuthClient 를 Controller 로 빼내기

* refactor: 불필요한 인터페이스(메소드) 제거
  • Loading branch information
tco0427 authored Sep 30, 2022
1 parent 3dfeb32 commit 28c0d44
Show file tree
Hide file tree
Showing 8 changed files with 58 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import com.woowacourse.moamoa.auth.config.AuthenticatedMemberId;
import com.woowacourse.moamoa.auth.service.AuthService;
import com.woowacourse.moamoa.auth.service.oauthclient.OAuthClient;
import com.woowacourse.moamoa.auth.service.oauthclient.response.GithubProfileResponse;
import com.woowacourse.moamoa.auth.service.response.AccessTokenResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
Expand All @@ -15,10 +17,14 @@
public class AuthController {

private final AuthService authService;
private final OAuthClient oAuthClient;

@PostMapping("/api/auth/login")
public ResponseEntity<AccessTokenResponse> login(@RequestParam final String code) {
return ResponseEntity.ok().body(authService.createToken(code));
final GithubProfileResponse profile = oAuthClient.getProfile(code);
final AccessTokenResponse token = authService.createToken(profile);

return ResponseEntity.ok().body(token);
}

@GetMapping("/api/auth/refresh")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,35 @@ public GithubOAuthClient(
this.restTemplate = restTemplate;
}

@Override
public GithubProfileResponse getProfile(final String code) {
final String accessToken = getAccessToken(code);
HttpHeaders headers = new HttpHeaders();
headers.add("Accept", MediaType.APPLICATION_JSON_VALUE);
headers.add("Authorization", "token " + accessToken);

HttpEntity<Void> httpEntity = new HttpEntity<>(headers);

try {
final ResponseEntity<GithubProfileResponse> response = restTemplate.exchange(
PROFILE_URL, HttpMethod.GET, httpEntity, GithubProfileResponse.class);

if (response.getStatusCode().is2xxSuccessful()) {
return Objects.requireNonNull(response.getBody());
}
throw new UnauthorizedException("Github에서 사용자 정보를 가져올 수 없습니다.");
} catch (HttpClientErrorException e) {
throw new UnauthorizedException("Github에서 사용자 정보를 가져올 수 없습니다.");
}
}

/*
Github에서 유효하지 않는 Authorization Code로 Access Token을 요청 시 200 응답이 오고,
body로 error, error_description, error_uri가 담겨서 온다.
에러 처리를 위해서는 body의 필드를 확인하여 처리해야 하므로 Map을 사용했다.
Access Token 요청이 정상적인 경우 body로 access_token, token_type, scope를 응답한다.
*/
@Override
public String getAccessToken(final String code) {
private String getAccessToken(final String code) {
final AccessTokenRequest accessTokenRequest = new AccessTokenRequest(clientId, clientSecret, code);

final HttpHeaders headers = new HttpHeaders();
Expand All @@ -67,25 +88,4 @@ public String getAccessToken(final String code) {
throw new UnauthorizedException("Access Token을 가져올 수 없습니다.");
}
}

@Override
public GithubProfileResponse getProfile(final String accessToken) {
HttpHeaders headers = new HttpHeaders();
headers.add("Accept", MediaType.APPLICATION_JSON_VALUE);
headers.add("Authorization", "token " + accessToken);

HttpEntity<Void> httpEntity = new HttpEntity<>(headers);

try {
final ResponseEntity<GithubProfileResponse> response = restTemplate.exchange(
PROFILE_URL, HttpMethod.GET, httpEntity, GithubProfileResponse.class);

if (response.getStatusCode().is2xxSuccessful()) {
return Objects.requireNonNull(response.getBody());
}
throw new UnauthorizedException("Github에서 사용자 정보를 가져올 수 없습니다.");
} catch (HttpClientErrorException e) {
throw new UnauthorizedException("Github에서 사용자 정보를 가져올 수 없습니다.");
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.woowacourse.moamoa.auth.service;

import com.woowacourse.moamoa.auth.infrastructure.TokenProvider;
import com.woowacourse.moamoa.auth.service.oauthclient.OAuthClient;
import com.woowacourse.moamoa.auth.service.oauthclient.response.GithubProfileResponse;
import com.woowacourse.moamoa.auth.service.response.AccessTokenResponse;
import com.woowacourse.moamoa.auth.service.response.TokenResponse;
Expand All @@ -19,14 +18,11 @@
public class AuthService {

private final MemberService memberService;
private final TokenProvider tokenProvider;
private final OAuthClient oAuthClient;
private final MemberRepository memberRepository;
private final TokenProvider tokenProvider;

@Transactional
public AccessTokenResponse createToken(final String code) {
final String accessToken = oAuthClient.getAccessToken(code);
final GithubProfileResponse githubProfileResponse = oAuthClient.getProfile(accessToken);
public AccessTokenResponse createToken(final GithubProfileResponse githubProfileResponse) {
final MemberResponse memberResponse = memberService.saveOrUpdate(githubProfileResponse.toMember());
final Long memberId = memberResponse.getId();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,5 @@

public interface OAuthClient {

String getAccessToken(final String code);
GithubProfileResponse getProfile(final String accessToken);
GithubProfileResponse getProfile(final String code);
}
3 changes: 2 additions & 1 deletion backend/src/test/java/com/woowacourse/moamoa/WebMVCTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.woowacourse.moamoa.auth.controller.interceptor.PathMatcherContainer;
import com.woowacourse.moamoa.auth.controller.interceptor.PathMatcherInterceptor;
import com.woowacourse.moamoa.auth.infrastructure.GithubOAuthClient;
import com.woowacourse.moamoa.auth.infrastructure.JwtTokenProvider;
import com.woowacourse.moamoa.auth.infrastructure.TokenProvider;
import com.woowacourse.moamoa.common.MockedServiceObjectsBeanRegister;
Expand All @@ -28,7 +29,7 @@
import org.springframework.web.context.request.NativeWebRequest;

@WebMvcTest(includeFilters = @Filter(type = FilterType.ANNOTATION, classes = RestController.class))
@Import({JwtTokenProvider.class, PathMatcherContainer.class, MockedServiceObjectsBeanRegister.class})
@Import({JwtTokenProvider.class, GithubOAuthClient.class, PathMatcherContainer.class, MockedServiceObjectsBeanRegister.class})
public abstract class WebMVCTest {

@Autowired
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import com.woowacourse.moamoa.WebMVCTest;
import com.woowacourse.moamoa.auth.service.oauthclient.OAuthClient;
import com.woowacourse.moamoa.auth.service.oauthclient.response.GithubProfileResponse;
import com.woowacourse.moamoa.auth.service.AuthService;
import com.woowacourse.moamoa.auth.service.response.AccessTokenResponse;
import org.junit.jupiter.api.DisplayName;
Expand All @@ -18,11 +20,19 @@ class AuthControllerTest extends WebMVCTest {
@MockBean
AuthService authService;

@MockBean
OAuthClient oAuthClient;

@DisplayName("Authorization 요청과 응답 형식을 확인한다.")
@Test
void getJwtToken() throws Exception {
given(authService.createToken("Authorization code"))
.willReturn(new AccessTokenResponse("jwt token", 30000));
final GithubProfileResponse dwoo = new GithubProfileResponse(1L, "dwoo", "http://imageUrl",
"http://profileUrl");

given(oAuthClient.getProfile("Authorization code"))
.willReturn(dwoo);
given(authService.createToken(dwoo))
.willReturn(new AccessTokenResponse("jwt token", 10L));

mockMvc.perform(post("/api/auth/login?code=Authorization code"))
.andExpect(status().isOk())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,36 +46,25 @@ void setUp() {
mockServer = MockRestServiceServer.createServer(restTemplate);
}

@DisplayName("Authorization code를 받아서 access token을 발급한다.")
@DisplayName("token을 받아서 사용자 프로필을 조회한다.")
@Test
void getAccessToken() throws JsonProcessingException {
void getProfile() throws JsonProcessingException {
final Map<String, String> accessTokenResponse = Map.of("access_token", "access-token", "token_type", "bearer", "scope", "");
final GithubProfileResponse profileResponse = new GithubProfileResponse(1L, "sc0116", "https://image", "github.com");

mockServer.expect(requestTo("https://github.com/login/oauth/access_token"))
.andExpect(method(HttpMethod.POST))
.andRespond(withStatus(HttpStatus.OK)
.contentType(MediaType.APPLICATION_JSON)
.body(objectMapper.writeValueAsString(accessTokenResponse)));

final String accessToken = oAuthClient.getAccessToken("code");

mockServer.verify();

assertThat(accessTokenResponse).containsEntry("access_token", accessToken);
}

@DisplayName("token을 받아서 사용자 프로필을 조회한다.")
@Test
void getProfile() throws JsonProcessingException {
final GithubProfileResponse profileResponse = new GithubProfileResponse(1L, "sc0116", "https://image", "github.com");

mockServer.expect(requestTo("https://api.github.com/user"))
.andExpect(method(HttpMethod.GET))
.andRespond(withStatus(HttpStatus.OK)
.contentType(MediaType.APPLICATION_JSON)
.body(objectMapper.writeValueAsString(profileResponse)));

final GithubProfileResponse response = oAuthClient.getProfile("token");
final GithubProfileResponse response = oAuthClient.getProfile("code");

mockServer.verify();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.woowacourse.moamoa.studyroom.webmvc;

import static org.springframework.http.HttpHeaders.AUTHORIZATION;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
Expand All @@ -10,7 +11,6 @@
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.springframework.http.HttpHeaders;

class GettingArticleControllerWebMvcTest extends WebMVCTest {

Expand All @@ -20,7 +20,7 @@ class GettingArticleControllerWebMvcTest extends WebMVCTest {
void unauthorizedGetArticleByInvalidToken(String token) throws Exception {
mockMvc.perform(
get("/api/studies/{study-id}/community/articles/{article-id}", 1L, 1L)
.header(HttpHeaders.AUTHORIZATION, token)
.header(AUTHORIZATION, token)
)
.andExpect(status().isUnauthorized())
.andDo(print());
Expand All @@ -34,7 +34,7 @@ void badRequestByInvalidIdFormat(String studyId, String articleId) throws Except

mockMvc.perform(
get("/api/studies/{study-id}/community/articles/{article-id}", studyId, articleId)
.header(HttpHeaders.AUTHORIZATION, token)
.header(AUTHORIZATION, token)
)
.andExpect(status().isBadRequest())
.andDo(print());
Expand All @@ -46,7 +46,7 @@ void badRequestByInvalidIdFormat(String studyId, String articleId) throws Except
void unauthorizedGetArticleListByInvalidToken(String token) throws Exception {
mockMvc.perform(
get("/api/studies/{study-id}/community/articles?page=0&size=3", 1L)
.header(HttpHeaders.AUTHORIZATION, token)
.header(AUTHORIZATION, token)
)
.andExpect(status().isUnauthorized())
.andDo(print());
Expand All @@ -59,7 +59,7 @@ void badRequestByInvalidIdFormat() throws Exception {

mockMvc.perform(
get("/api/studies/{study-id}/community/articles", "one")
.header(HttpHeaders.AUTHORIZATION, token)
.header(AUTHORIZATION, token)
)
.andExpect(status().isBadRequest())
.andDo(print());
Expand All @@ -73,7 +73,7 @@ void badRequestByInvalidFormatParam(String page, String size) throws Exception {

mockMvc.perform(
get("/api/studies/{study-id}/community/articles", "1")
.header(HttpHeaders.AUTHORIZATION, token)
.header(AUTHORIZATION, token)
.param("page", page)
.param("size", size)
)
Expand All @@ -88,7 +88,7 @@ void badRequestByEmptyPage() throws Exception {

mockMvc.perform(
get("/api/studies/{study-id}/community/articles", "1")
.header(HttpHeaders.AUTHORIZATION, token)
.header(AUTHORIZATION, token)
.param("page", "")
.param("size", "5")
)
Expand Down

0 comments on commit 28c0d44

Please sign in to comment.