Skip to content

Commit

Permalink
[Feature/BE] 어드민 로그인 api 구현 (#717)
Browse files Browse the repository at this point in the history
[BE] 어드민 로그인 api 구현 (#716)

feat: 어드민 로그인 api 구현
  • Loading branch information
Ohzzi committed Oct 7, 2022
1 parent ca4c493 commit f125bb8
Show file tree
Hide file tree
Showing 7 changed files with 173 additions and 17 deletions.
8 changes: 8 additions & 0 deletions backend/src/docs/asciidoc/auth.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@

operation::auth-login[snippets='http-request,http-response']

=== 어드민 로그인

==== 발생 가능 에러

- 40300, 40410, 50000, 50001

operation::auth-admin-login[snippets='http-request,http-response']

=== 액세스 토큰 발급

==== 발생 가능 에러
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
import com.woowacourse.f12.domain.member.Member;
import com.woowacourse.f12.domain.member.MemberRepository;
import com.woowacourse.f12.domain.member.Role;
import com.woowacourse.f12.dto.response.auth.AdminLoginResponse;
import com.woowacourse.f12.dto.response.auth.GitHubProfileResponse;
import com.woowacourse.f12.dto.response.auth.IssuedTokensResponse;
import com.woowacourse.f12.dto.result.LoginResult;
import com.woowacourse.f12.exception.forbidden.NotAdminException;
import com.woowacourse.f12.exception.notfound.MemberNotFoundException;
import com.woowacourse.f12.exception.unauthorized.RefreshTokenExpiredException;
import com.woowacourse.f12.exception.unauthorized.RefreshTokenInvalidException;
Expand Down Expand Up @@ -47,6 +49,17 @@ public LoginResult login(final String code) {
return new LoginResult(refreshToken.getRefreshToken(), applicationAccessToken, member);
}

public AdminLoginResponse loginAdmin(final String code) {
final GitHubProfileResponse gitHubProfileResponse = getGitHubProfileResponse(code);
final Member member = memberRepository.findByGitHubId(gitHubProfileResponse.getGitHubId())
.orElseThrow(MemberNotFoundException::new);
if (!member.isAdmin()) {
throw new NotAdminException();
}
final String applicationAccessToken = jwtProvider.createAccessToken(member.getId(), member.getRole());
return new AdminLoginResponse(applicationAccessToken);
}

private GitHubProfileResponse getGitHubProfileResponse(final String code) {
final String gitHubAccessToken = gitHubOauthClient.getAccessToken(code);
return gitHubOauthClient.getProfile(gitHubAccessToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,10 @@ public void updateInventoryProducts(final List<InventoryProduct> values) {
this.inventoryProducts = new InventoryProducts(values);
}

public boolean isAdmin() {
return this.role == Role.ADMIN;
}

@Override
public boolean equals(final Object o) {
if (this == o) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.woowacourse.f12.dto.response.auth;

import lombok.Getter;

@Getter
public class AdminLoginResponse {

private final String accessToken;

public AdminLoginResponse(final String accessToken) {
this.accessToken = accessToken;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import com.woowacourse.f12.application.auth.AuthService;
import com.woowacourse.f12.dto.response.AccessTokenResponse;
import com.woowacourse.f12.dto.response.auth.AdminLoginResponse;
import com.woowacourse.f12.dto.response.auth.IssuedTokensResponse;
import com.woowacourse.f12.dto.response.auth.LoginResponse;
import com.woowacourse.f12.dto.result.LoginResult;
Expand Down Expand Up @@ -31,15 +32,19 @@ public AuthController(final AuthService authService, final RefreshTokenCookiePro
}

@GetMapping("/login")
public ResponseEntity<LoginResponse> login(final HttpServletRequest request,
final HttpServletResponse response,
@RequestParam final String code) {
public ResponseEntity<LoginResponse> login(final HttpServletResponse response, @RequestParam final String code) {
final LoginResult loginResult = authService.login(code);
final String refreshToken = loginResult.getRefreshToken();
refreshTokenCookieProvider.setCookie(response, refreshToken);
return ResponseEntity.ok(LoginResponse.from(loginResult));
}

@GetMapping("/login/admin")
public ResponseEntity<AdminLoginResponse> loginAdmin(@RequestParam final String code) {
final AdminLoginResponse adminLoginResponse = authService.loginAdmin(code);
return ResponseEntity.ok(adminLoginResponse);
}

@GetMapping("/logout")
public ResponseEntity<Void> logout(final HttpServletRequest request, final HttpServletResponse response) {
refreshTokenCookieProvider.removeCookie(request, response);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.woowacourse.f12.application.auth;

import static com.woowacourse.f12.support.fixture.MemberFixture.ADMIN_KLAY;
import static com.woowacourse.f12.support.fixture.MemberFixture.CORINNE;
import static com.woowacourse.f12.support.fixture.MemberFixture.CORINNE_UPDATED;
import static org.assertj.core.api.Assertions.assertThat;
Expand All @@ -18,9 +19,11 @@
import com.woowacourse.f12.domain.member.Member;
import com.woowacourse.f12.domain.member.MemberRepository;
import com.woowacourse.f12.domain.member.Role;
import com.woowacourse.f12.dto.response.auth.AdminLoginResponse;
import com.woowacourse.f12.dto.response.auth.GitHubProfileResponse;
import com.woowacourse.f12.dto.response.auth.IssuedTokensResponse;
import com.woowacourse.f12.dto.result.LoginResult;
import com.woowacourse.f12.exception.forbidden.NotAdminException;
import com.woowacourse.f12.exception.unauthorized.RefreshTokenExpiredException;
import com.woowacourse.f12.exception.unauthorized.RefreshTokenInvalidException;
import java.time.LocalDateTime;
Expand Down Expand Up @@ -133,6 +136,64 @@ class AuthServiceTest {
);
}

@Test
void 깃허브_코드가_들어왔을때_회원정보가_있고_롤이_어드민이면_어드민_로그인을_진행하고_토큰을_반환한다() {
// given
String code = "abcde";
String accessToken = "accessToken";
String applicationToken = "applicationToken";

GitHubProfileResponse gitHubProfile = CORINNE_UPDATED.깃허브_프로필();
Member member = ADMIN_KLAY.생성(memberId);

given(gitHubOauthClient.getAccessToken(code))
.willReturn(accessToken);
given(gitHubOauthClient.getProfile(accessToken))
.willReturn(gitHubProfile);
given(memberRepository.findByGitHubId(gitHubProfile.getGitHubId()))
.willReturn(Optional.of(member));
given(jwtProvider.createAccessToken(member.getId(), member.getRole()))
.willReturn(applicationToken);

// when
AdminLoginResponse adminLoginResponse = authService.loginAdmin(code);

// then
assertAll(
() -> assertThat(adminLoginResponse.getAccessToken()).isEqualTo(applicationToken),
() -> verify(gitHubOauthClient).getAccessToken(code),
() -> verify(gitHubOauthClient).getProfile(accessToken),
() -> verify(memberRepository).findByGitHubId(gitHubProfile.getGitHubId()),
() -> verify(jwtProvider).createAccessToken(memberId, member.getRole())
);
}

@Test
void 깃허브_코드가_들어왔을때_어드민_롤이_아닌경우_어드민_로그인을_실패하고_예외가_발생한다() {
// given
String code = "abcde";
String accessToken = "accessToken";

GitHubProfileResponse gitHubProfile = CORINNE_UPDATED.깃허브_프로필();
Member member = CORINNE.생성(memberId);

given(gitHubOauthClient.getAccessToken(code))
.willReturn(accessToken);
given(gitHubOauthClient.getProfile(accessToken))
.willReturn(gitHubProfile);
given(memberRepository.findByGitHubId(gitHubProfile.getGitHubId()))
.willReturn(Optional.of(member));

// when, then
assertAll(
() -> assertThatThrownBy(() -> authService.loginAdmin(code))
.isExactlyInstanceOf(NotAdminException.class),
() -> verify(gitHubOauthClient).getAccessToken(code),
() -> verify(gitHubOauthClient).getProfile(accessToken),
() -> verify(memberRepository).findByGitHubId(gitHubProfile.getGitHubId())
);
}

@Test
void 유효한_리프레시_토큰으로_액세스_토큰을_발급한다() {
// given
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,32 @@
package com.woowacourse.f12.presentation.auth;

import static com.woowacourse.f12.support.fixture.MemberFixture.CORINNE;
import static org.hamcrest.Matchers.containsString;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.verify;
import static org.mockito.Mockito.times;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.cookie;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import com.woowacourse.f12.application.auth.AuthService;
import com.woowacourse.f12.dto.response.auth.AdminLoginResponse;
import com.woowacourse.f12.dto.response.auth.IssuedTokensResponse;
import com.woowacourse.f12.dto.response.auth.LoginResponse;
import com.woowacourse.f12.dto.result.LoginResult;
import com.woowacourse.f12.exception.ErrorCode;
import com.woowacourse.f12.exception.badrequest.InvalidGitHubLoginException;
import com.woowacourse.f12.exception.forbidden.NotAdminException;
import com.woowacourse.f12.exception.internalserver.GitHubServerException;
import com.woowacourse.f12.exception.unauthorized.RefreshTokenInvalidException;
import com.woowacourse.f12.presentation.PresentationTest;
import javax.servlet.http.Cookie;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
Expand All @@ -17,20 +35,6 @@
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;

import javax.servlet.http.Cookie;

import static com.woowacourse.f12.support.fixture.MemberFixture.CORINNE;
import static org.hamcrest.Matchers.containsString;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.verify;
import static org.mockito.Mockito.times;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@WebMvcTest(AuthController.class)
class AuthControllerTest extends PresentationTest {

Expand Down Expand Up @@ -128,6 +132,54 @@ class AuthControllerTest extends PresentationTest {
verify(authService).login(code);
}

@Test
void 어드민_로그인_성공() throws Exception {
// given
String code = "code";
String token = "token";
AdminLoginResponse adminLoginResponse = new AdminLoginResponse(token);

given(authService.loginAdmin(code))
.willReturn(adminLoginResponse);

// when
ResultActions resultActions = mockMvc.perform(
get("/api/v1/login/admin?code=" + code)
);

// then
resultActions
.andExpect(status().isOk())
.andDo(print())
.andDo(
document("auth-admin-login")
);

verify(authService).loginAdmin(code);
}

@Test
void 어드민_로그인_실패_어드민이_아닌_경우() throws Exception {
// given
String code = "code";
String token = "token";

given(authService.loginAdmin(code))
.willThrow(new NotAdminException());

// when
ResultActions resultActions = mockMvc.perform(
get("/api/v1/login/admin?code=" + code)
);

// then
resultActions
.andExpect(status().isForbidden())
.andDo(print());

verify(authService).loginAdmin(code);
}

@Test
void 리프레시_토큰으로_액세스_토큰을_발급() throws Exception {
// given
Expand Down

0 comments on commit f125bb8

Please sign in to comment.