Skip to content
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

[Feature/BE] 어드민 로그인 api 구현 #717

Merged
merged 1 commit into from
Oct 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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