Skip to content

Commit

Permalink
모든 API 인증 기능 추가 (#202)
Browse files Browse the repository at this point in the history
* refactor: FeedbackController 에 사용하지 않는 변수 삭제

* refactor: runnerPost auth 어노테이션 붙이기

* refactor: 게시물 상세 조회 시 auth 선택적으로 적용하도록 변경

* refactor: 게시물 수정, 삭제 시에 Auth 어노테이션 추가

* refactor: 서포터 전체 조회 반환 필드 변경

* test: 변경 사항에 따른 테스트 코드 변경
  • Loading branch information
shb03323 authored Aug 3, 2023
1 parent afe83da commit 3efdaab
Show file tree
Hide file tree
Showing 18 changed files with 105 additions and 157 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import touch.baton.domain.feedback.service.SupporterFeedBackCreateRequest;
import touch.baton.domain.oauth.controller.resolver.AuthRunnerPrincipal;
import touch.baton.domain.runner.Runner;
import touch.baton.domain.runner.service.RunnerService;

import java.net.URI;

Expand All @@ -22,7 +21,6 @@
public class FeedbackController {

private final FeedbackService feedbackService;
private final RunnerService runnerService;

@PostMapping("/supporter")
public ResponseEntity<Void> createSupporterFeedback(@AuthRunnerPrincipal final Runner runner,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface AuthRunnerPrincipal {

boolean required() default true;
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ public Object resolveArgument(final MethodParameter parameter,
) throws Exception {
final String authHeader = webRequest.getHeader(AUTHORIZATION);

// FIXME: 2023/08/03 null 말고 GUEST, USER, ADMIN role 추가해야할 것 같아요.
if (!Objects.requireNonNull(parameter.getParameterAnnotation(AuthRunnerPrincipal.class)).required()) {
return getRunnerIfExist(authHeader);
}

if (Objects.isNull(authHeader)) {
throw new OauthRequestException(ClientErrorCode.OAUTH_AUTHORIZATION_VALUE_IS_NULL);
}
Expand All @@ -55,4 +60,22 @@ public Object resolveArgument(final MethodParameter parameter,

return foundRunner;
}

// FIXME: 2023/08/03 예쁘게 고치기
private Runner getRunnerIfExist(final String authHeader) {
if (Objects.isNull(authHeader)) {
return null;
}
if (!authHeader.startsWith(BEARER)) {
throw new OauthRequestException(ClientErrorCode.OAUTH_AUTHORIZATION_BEARER_TYPE_NOT_FOUND);
}

final String token = authHeader.substring(BEARER.length());
final Claims claims = jwtDecoder.parseJwtToken(token);
final String email = claims.get("email", String.class);
final Runner foundRunner = oauthRunnerRepository.joinByMemberSocialId(email)
.orElseThrow(() -> new OauthRequestException(ClientErrorCode.JWT_CLAIM_SOCIAL_ID_IS_WRONG));

return foundRunner;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface AuthSupporterPrincipal {

boolean required() default true;
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ public Object resolveArgument(final MethodParameter parameter,
final WebDataBinderFactory binderFactory
) throws Exception {
final String authHeader = webRequest.getHeader(AUTHORIZATION);
// FIXME: 2023/08/03 null 말고 GUEST, USER, ADMIN role 추가해야할 것 같아요.
if (!Objects.requireNonNull(parameter.getParameterAnnotation(AuthRunnerPrincipal.class)).required()) {
return getSupporterIfExist(authHeader);
}

if (Objects.isNull(authHeader)) {
throw new OauthRequestException(ClientErrorCode.OAUTH_AUTHORIZATION_VALUE_IS_NULL);
Expand All @@ -55,4 +59,21 @@ public Object resolveArgument(final MethodParameter parameter,

return foundSupporter;
}

private Supporter getSupporterIfExist(final String authHeader) {
if (Objects.isNull(authHeader)) {
return null;
}
if (!authHeader.startsWith(BEARER)) {
throw new OauthRequestException(ClientErrorCode.OAUTH_AUTHORIZATION_BEARER_TYPE_NOT_FOUND);
}

final String token = authHeader.substring(BEARER.length());
final Claims claims = jwtDecoder.parseJwtToken(token);
final String email = claims.get("email", String.class);
final Supporter foundSupporter = oauthSupporterRepository.joinByMemberSocialId(email)
.orElseThrow(() -> new OauthRequestException(ClientErrorCode.JWT_CLAIM_SOCIAL_ID_IS_WRONG));

return foundSupporter;
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.util.UriComponentsBuilder;
import touch.baton.domain.oauth.controller.resolver.AuthRunnerPrincipal;
import touch.baton.domain.runner.Runner;
import touch.baton.domain.runner.service.RunnerService;
import touch.baton.domain.runnerpost.RunnerPost;
import touch.baton.domain.runnerpost.controller.response.RunnerPostReadResponses;
import touch.baton.domain.runnerpost.controller.response.RunnerPostResponse;
import touch.baton.domain.runnerpost.service.RunnerPostService;
Expand All @@ -30,15 +31,12 @@
public class RunnerPostController {

private final RunnerPostService runnerPostService;
private final RunnerService runnerService;

@PostMapping
public ResponseEntity<Void> createRunnerPost(@Valid @RequestBody RunnerPostCreateRequest request) {
// TODO 07/19 로그인 기능 개발시 1L 변경 요망
Runner runner = runnerService.readRunnerWithMember(1L);

public ResponseEntity<Void> createRunnerPost(@AuthRunnerPrincipal final Runner runner,
@Valid @RequestBody final RunnerPostCreateRequest request
) {
final Long savedId = runnerPostService.createRunnerPost(runner, request);

final URI redirectUri = UriComponentsBuilder.fromPath("/api/v1/posts/runner")
.path("/{id}")
.buildAndExpand(savedId)
Expand All @@ -47,12 +45,10 @@ public ResponseEntity<Void> createRunnerPost(@Valid @RequestBody RunnerPostCreat
}

@PostMapping("/test")
public ResponseEntity<Void> createRunnerPostVersionTest(@Valid @RequestBody RunnerPostCreateTestRequest request) {
// TODO 07/19 로그인 기능 개발시 1L 변경 요망
Runner runner = runnerService.readRunnerWithMember(1L);

public ResponseEntity<Void> createRunnerPostVersionTest(@AuthRunnerPrincipal final Runner runner,
@Valid @RequestBody final RunnerPostCreateTestRequest request
) {
final Long savedId = runnerPostService.createRunnerPostTest(runner, request);

final URI redirectUri = UriComponentsBuilder.fromPath("/api/v1/posts/runner")
.path("/{id}")
.buildAndExpand(savedId)
Expand All @@ -61,33 +57,46 @@ public ResponseEntity<Void> createRunnerPostVersionTest(@Valid @RequestBody Runn
}

@GetMapping("/{runnerPostId}")
public ResponseEntity<RunnerPostResponse.Detail> readByRunnerPostId(@PathVariable final Long runnerPostId) {
final RunnerPostResponse.Detail response
= RunnerPostResponse.Detail.from(runnerPostService.readByRunnerPostId(runnerPostId));
public ResponseEntity<RunnerPostResponse.Detail> readByRunnerPostId(@AuthRunnerPrincipal(required = false) final Runner runner,
@PathVariable final Long runnerPostId
) {
final RunnerPost runnerPost = runnerPostService.readByRunnerPostId(runnerPostId);
final RunnerPostResponse.Detail response = RunnerPostResponse.Detail.of(
runnerPost,
runnerPost.getRunner().equals(runner)
);

return ResponseEntity.ok(response);
}

@GetMapping("/{runnerPostId}/test")
public ResponseEntity<RunnerPostResponse.DetailVersionTest> readByRunnerPostIdVersionTest(@PathVariable final Long runnerPostId) {
final RunnerPostResponse.DetailVersionTest response
= RunnerPostResponse.DetailVersionTest.fromVersionTest(runnerPostService.readByRunnerPostId(runnerPostId));
public ResponseEntity<RunnerPostResponse.DetailVersionTest> readByRunnerPostIdVersionTest(@AuthRunnerPrincipal(required = false) final Runner runner,
@PathVariable final Long runnerPostId
) {
final RunnerPost runnerPost = runnerPostService.readByRunnerPostId(runnerPostId);
final RunnerPostResponse.DetailVersionTest response = RunnerPostResponse.DetailVersionTest.ofVersionTest(
runnerPost,
runnerPost.getRunner().equals(runner)
);

return ResponseEntity.ok(response);
}

@DeleteMapping("/{runnerPostId}")
public ResponseEntity<Void> deleteByRunnerPostId(@PathVariable final Long runnerPostId) {
runnerPostService.deleteByRunnerPostId(runnerPostId);
public ResponseEntity<Void> deleteByRunnerPostId(@AuthRunnerPrincipal final Runner runner,
@PathVariable final Long runnerPostId
) {
runnerPostService.deleteByRunnerPostId(runnerPostId, runner);

return ResponseEntity.noContent().build();
}

@PutMapping("/{runnerPostId}")
public ResponseEntity<Void> update(@PathVariable final Long runnerPostId,
public ResponseEntity<Void> update(@AuthRunnerPrincipal Runner runner,
@PathVariable final Long runnerPostId,
@Valid @RequestBody final RunnerPostUpdateRequest request
) {
final Long updatedId = runnerPostService.updateRunnerPost(runnerPostId, request);
final Long updatedId = runnerPostService.updateRunnerPost(runnerPostId, runner, request);
final URI redirectUri = UriComponentsBuilder.fromPath("/api/v1/posts/runner")
.path("/{runnerPostId}")
.buildAndExpand(updatedId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public record Detail(Long runnerPostId,
List<String> tags
) {

public static Detail from(final RunnerPost runnerPost) {
public static Detail of(final RunnerPost runnerPost, final boolean isOwner) {
return new Detail(
runnerPost.getId(),
runnerPost.getTitle().getValue(),
Expand All @@ -32,7 +32,7 @@ public static Detail from(final RunnerPost runnerPost) {
runnerPost.getWatchedCount().getValue(),
runnerPost.getChattingCount().getValue(),
runnerPost.getReviewStatus(),
true,
isOwner,
RunnerResponse.Detail.from(runnerPost.getRunner()),
convertToTags(runnerPost)
);
Expand All @@ -53,7 +53,7 @@ public record DetailVersionTest(Long runnerPostId,
boolean isOwner,
List<String> tags
) {
public static DetailVersionTest fromVersionTest(final RunnerPost runnerPost) {
public static DetailVersionTest ofVersionTest(final RunnerPost runnerPost, final boolean isOwner) {
return new DetailVersionTest(
runnerPost.getId(),
runnerPost.getTitle().getValue(),
Expand All @@ -65,7 +65,7 @@ public static DetailVersionTest fromVersionTest(final RunnerPost runnerPost) {
runnerPost.getReviewStatus(),
RunnerResponse.Detail.from(runnerPost.getRunner()),
SupporterResponseTestVersion.Simple.fromTestVersion(runnerPost.getSupporter()),
true,
isOwner,
convertToTags(runnerPost)
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,15 +119,17 @@ public Long createRunnerPostTest(final Runner runner, final RunnerPostCreateTest

public RunnerPost readByRunnerPostId(final Long runnerPostId) {
runnerPostTagRepository.joinTagByRunnerPostId(runnerPostId);
final RunnerPost findRunnerPost = runnerPostRepository.joinMemberByRunnerPostId(runnerPostId).orElseThrow(() -> new RunnerPostBusinessException("RunnerPost 의 식별자값으로 러너 게시글을 조회할 수 없습니다."));
final RunnerPost findRunnerPost = runnerPostRepository.joinMemberByRunnerPostId(runnerPostId)
.orElseThrow(() -> new RunnerPostBusinessException("RunnerPost 의 식별자값으로 러너 게시글을 조회할 수 없습니다."));

findRunnerPost.increaseWatchedCount();

return findRunnerPost;
}

@Transactional
public void deleteByRunnerPostId(final Long runnerPostId) {
public void deleteByRunnerPostId(final Long runnerPostId, final Runner runner) {
// FIXME: 2023/08/03 삭제 시 본인인지 확인하는 로직 넣기
final Optional<RunnerPost> maybeRunnerPost = runnerPostRepository.findById(runnerPostId);
if (maybeRunnerPost.isEmpty()) {
throw new RunnerPostBusinessException("RunnerPost 의 식별자값으로 삭제할 러너 게시글이 존재하지 않습니다.");
Expand All @@ -142,8 +144,9 @@ public void deleteByRunnerPostId(final Long runnerPostId) {
}

@Transactional
public Long updateRunnerPost(final Long runnerPostId, final RunnerPostUpdateRequest request) {
public Long updateRunnerPost(final Long runnerPostId, final Runner runner, final RunnerPostUpdateRequest request) {
// TODO: 메소드 분리
// FIXME: 2023/08/03 주인 확인 로직 넣기
final RunnerPost runnerPost = runnerPostRepository.findById(runnerPostId)
.orElseThrow(() -> new IllegalArgumentException("해당 runnerPostId 로 러너 게시글을 찾을 수 없습니다. runnerPostId를 다시 확인해주세요"));
runnerPost.updateTitle(new Title(request.title()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import touch.baton.domain.supporter.Supporter;
import touch.baton.domain.technicaltag.SupporterTechnicalTag;
import touch.baton.domain.technicaltag.SupporterTechnicalTags;

import java.util.List;

Expand All @@ -14,7 +13,7 @@ public record Detail(Long supporterId,
int reviewCount,
String githubUrl,
String introduction,
List<String> supporterTechnicalTags
List<String> technicalTags
) {

public static Detail from(final Supporter supporter) {
Expand All @@ -25,11 +24,11 @@ public static Detail from(final Supporter supporter) {
supporter.getReviewCount().getValue(),
supporter.getMember().getGithubUrl().getValue(),
supporter.getIntroduction().getValue(),
getSupporterTechnicalTagsName(supporter)
getTechnicalTagsName(supporter)
);
}

private static List<String> getSupporterTechnicalTagsName(Supporter supporter) {
private static List<String> getTechnicalTagsName(final Supporter supporter) {
return supporter.getSupporterTechnicalTags().getSupporterTechnicalTags()
.stream()
.map(SupporterTechnicalTag::getTechnicalTag)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package touch.baton.assure.runnerpost;

import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import touch.baton.config.AssuredTestConfig;
import touch.baton.domain.common.vo.Grade;
Expand Down Expand Up @@ -27,6 +28,7 @@

class RunnerPostAssuredDeleteTest extends AssuredTestConfig {

@Disabled
@Test
void 러너의_게시글_식별자값으로_러너_게시글_상세_정보_삭제에_성공한다() {
final Member member = MemberFixture.createHyena();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package touch.baton.assure.runnerpost;

import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import touch.baton.config.AssuredTestConfig;
import touch.baton.domain.common.vo.Grade;
Expand All @@ -25,6 +26,7 @@
@SuppressWarnings("NonAsciiCharacters")
class RunnerPostAssuredReadTest extends AssuredTestConfig {

@Disabled
@Test
void 러너의_게시글_식별자값으로_러너_게시글_상세_정보_조회에_성공한다() {
final Member memberHyena = memberRepository.save(MemberFixture.createHyena());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.mock.mockito.MockBean;
import touch.baton.config.RestdocsConfig;
import touch.baton.config.MockMvcTest;
import touch.baton.config.RestdocsConfig;
import touch.baton.domain.runner.Runner;
import touch.baton.domain.runner.service.RunnerService;
import touch.baton.domain.runnerpost.RunnerPost;
import touch.baton.domain.runnerpost.controller.RunnerPostController;
import touch.baton.domain.runnerpost.service.RunnerPostService;
Expand All @@ -24,9 +23,7 @@
import static org.mockito.Mockito.spy;
import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
import static org.springframework.restdocs.payload.JsonFieldType.ARRAY;
import static org.springframework.restdocs.payload.JsonFieldType.NUMBER;
import static org.springframework.restdocs.payload.JsonFieldType.STRING;
import static org.springframework.restdocs.payload.JsonFieldType.*;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
Expand All @@ -41,9 +38,6 @@ class RunnerPostReadApiTest extends RestdocsConfig {
@MockBean
private RunnerPostService runnerPostService;

@MockBean
private RunnerService runnerService;

@DisplayName("러너 게시글 전체 조회 API")
@Test
void readAllRunnerPosts() throws Exception {
Expand Down
Loading

0 comments on commit 3efdaab

Please sign in to comment.