diff --git a/backend/src/main/java/com/zzang/chongdae/auth/config/AuthWebMvcConfig.java b/backend/src/main/java/com/zzang/chongdae/auth/config/AuthWebMvcConfig.java index e16e2d8c3..b50b2e8e8 100644 --- a/backend/src/main/java/com/zzang/chongdae/auth/config/AuthWebMvcConfig.java +++ b/backend/src/main/java/com/zzang/chongdae/auth/config/AuthWebMvcConfig.java @@ -2,10 +2,12 @@ import com.zzang.chongdae.auth.controller.CookieConsumer; import com.zzang.chongdae.auth.service.AuthService; +import com.zzang.chongdae.auth.service.JwtTokenProvider; import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Configuration; import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @RequiredArgsConstructor @@ -14,9 +16,17 @@ public class AuthWebMvcConfig implements WebMvcConfigurer { private final AuthService authService; private final CookieConsumer cookieConsumer; + private final JwtTokenProvider jwtTokenProvider; @Override public void addArgumentResolvers(List resolvers) { resolvers.add(new MemberArgumentResolver(authService, cookieConsumer)); } + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(new AuthorizationInterceptor(cookieConsumer, jwtTokenProvider)) + .addPathPatterns("/**") + .excludePathPatterns("/auth/login", "/auth/signup"); + } } diff --git a/backend/src/main/java/com/zzang/chongdae/auth/config/AuthorizationInterceptor.java b/backend/src/main/java/com/zzang/chongdae/auth/config/AuthorizationInterceptor.java new file mode 100644 index 000000000..7a56b336c --- /dev/null +++ b/backend/src/main/java/com/zzang/chongdae/auth/config/AuthorizationInterceptor.java @@ -0,0 +1,22 @@ +package com.zzang.chongdae.auth.config; + +import com.zzang.chongdae.auth.controller.CookieConsumer; +import com.zzang.chongdae.auth.service.JwtTokenProvider; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.web.servlet.HandlerInterceptor; + +@RequiredArgsConstructor +public class AuthorizationInterceptor implements HandlerInterceptor { + + private final CookieConsumer cookieConsumer; + private final JwtTokenProvider jwtTokenProvider; + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { + String token = cookieConsumer.getAccessToken(request.getCookies()); + jwtTokenProvider.validateAccessToken(token); + return true; + } +} diff --git a/backend/src/main/java/com/zzang/chongdae/auth/service/JwtTokenProvider.java b/backend/src/main/java/com/zzang/chongdae/auth/service/JwtTokenProvider.java index a7cba4762..e51d3510b 100644 --- a/backend/src/main/java/com/zzang/chongdae/auth/service/JwtTokenProvider.java +++ b/backend/src/main/java/com/zzang/chongdae/auth/service/JwtTokenProvider.java @@ -54,6 +54,10 @@ private Date calculateExpiredAt(Duration expired) { return new Date(now.getTime() + expired.toMillis()); } + public void validateAccessToken(String token) { + getClaims(token, accessSecretKey).getSubject(); + } + public Long getMemberIdByAccessToken(String token) { String memberId = getClaims(token, accessSecretKey).getSubject(); return Long.valueOf(memberId); diff --git a/backend/src/main/java/com/zzang/chongdae/comment/service/CommentService.java b/backend/src/main/java/com/zzang/chongdae/comment/service/CommentService.java index 442fbddc2..971d2d9e6 100644 --- a/backend/src/main/java/com/zzang/chongdae/comment/service/CommentService.java +++ b/backend/src/main/java/com/zzang/chongdae/comment/service/CommentService.java @@ -37,12 +37,18 @@ public class CommentService { public Long saveComment(CommentSaveRequest request, MemberEntity member) { OfferingEntity offering = offeringRepository.findById(request.offeringId()) .orElseThrow(() -> new MarketException(OfferingErrorCode.NOT_FOUND)); - + validateIsJoined(member, offering); CommentEntity comment = new CommentEntity(member, offering, request.content()); CommentEntity savedComment = commentRepository.save(comment); return savedComment.getId(); } + private void validateIsJoined(MemberEntity member, OfferingEntity offering) { + if (!offeringMemberRepository.existsByOfferingAndMember(offering, member)) { + throw new MarketException(OfferingMemberErrorCode.NOT_FOUND); + } + } + public CommentRoomAllResponse getAllCommentRoom(MemberEntity member) { List commentRooms = offeringRepository.findCommentRoomsByMember(member); List responseItems = commentRooms.stream() @@ -66,12 +72,6 @@ public CommentRoomInfoResponse getCommentRoomInfo(Long offeringId, MemberEntity return new CommentRoomInfoResponse(offering, member); } - private void validateIsJoined(MemberEntity member, OfferingEntity offering) { - if (!offeringMemberRepository.existsByOfferingAndMember(offering, member)) { - throw new MarketException(OfferingMemberErrorCode.NOT_FOUND); - } - } - @Transactional public CommentRoomStatusResponse updateCommentRoomStatus(Long offeringId, MemberEntity member) { OfferingEntity offering = offeringRepository.findById(offeringId) @@ -93,7 +93,7 @@ private void validateIsProposer(MemberEntity member, OfferingEntity offering) { public CommentAllResponse getAllComment(Long offeringId, MemberEntity member) { OfferingEntity offering = offeringRepository.findById(offeringId) .orElseThrow(() -> new MarketException(OfferingErrorCode.NOT_FOUND)); - + validateIsJoined(member, offering); List comments = commentRepository.findAllByOfferingOrderByCreatedAt(offering); List responseItems = comments.stream() .map(comment -> new CommentAllResponseItem(comment, member)) diff --git a/backend/src/test/java/com/zzang/chongdae/comment/integration/CommentIntegrationTest.java b/backend/src/test/java/com/zzang/chongdae/comment/integration/CommentIntegrationTest.java index 34b58a9ee..be1ae47ae 100644 --- a/backend/src/test/java/com/zzang/chongdae/comment/integration/CommentIntegrationTest.java +++ b/backend/src/test/java/com/zzang/chongdae/comment/integration/CommentIntegrationTest.java @@ -52,6 +52,7 @@ class SaveComment { void setUp() { member = memberFixture.createMember(); offering = offeringFixture.createOffering(member); + offeringMemberFixture.createProposer(member, offering); } @DisplayName("댓글을 작성할 수 있다") diff --git a/backend/src/test/java/com/zzang/chongdae/offering/integration/OfferingIntegrationTest.java b/backend/src/test/java/com/zzang/chongdae/offering/integration/OfferingIntegrationTest.java index 7e7094bd1..fdddcab69 100644 --- a/backend/src/test/java/com/zzang/chongdae/offering/integration/OfferingIntegrationTest.java +++ b/backend/src/test/java/com/zzang/chongdae/offering/integration/OfferingIntegrationTest.java @@ -160,6 +160,7 @@ void setUp() { void should_responseAllOffering_when_givenPageInfo() { given(spec).log().all() .filter(document("get-all-offering-success", resource(successSnippets))) + .cookies(cookieProvider.createCookies()) .queryParam("filter", "RECENT") .queryParam("search", "title") .queryParam("last-id", 10) @@ -362,11 +363,17 @@ class GetAllOfferingFilter { .responseSchema(schema("OfferingFilterSuccessResponse")) .build(); + @BeforeEach + void setUp() { + memberFixture.createMember(); + } + @DisplayName("공모 id로 공모 일정 정보를 조회할 수 있다") @Test void should_responseOfferingFilter_when_givenOfferingId() { given(spec).log().all() .filter(document("get-all-offering-filter-success", resource(successSnippets))) + .cookies(cookieProvider.createCookies()) .when().get("/offerings/filters") .then().log().all() .statusCode(200); @@ -575,6 +582,11 @@ class ExtractProductImage { .responseSchema(schema("OfferingProductImageResponse")) .build(); + @BeforeEach + void setUp() { + memberFixture.createMember(); + } + @DisplayName("상품 링크를 받아 이미지를 추출합니다.") @Test void should_extractImageUrl_when_givenProductUrl() { @@ -582,6 +594,7 @@ void should_extractImageUrl_when_givenProductUrl() { given(spec).log().all() .filter(document("extract-product-image-success", resource(successSnippets))) + .cookies(cookieProvider.createCookies()) .contentType(ContentType.JSON) .body(request) .when().post("/offerings/product-images/og") @@ -596,6 +609,7 @@ void should_returnEmptyString_when_fail() { given(spec).log().all() .filter(document("extract-product-image-fail", resource(successSnippets))) + .cookies(cookieProvider.createCookies()) .contentType(ContentType.JSON) .body(request) .when().post("/offerings/product-images/og") @@ -610,6 +624,7 @@ void should_throwException_when_emptyValue() { given(spec).log().all() .filter(document("extract-product-image-fail-request-with-null", resource(failSnippets))) + .cookies(cookieProvider.createCookies()) .contentType(ContentType.JSON) .body(request) .when().post("/offerings/product-images/og") @@ -644,6 +659,7 @@ class UploadProductImage { @BeforeEach void setUp() { + memberFixture.createMember(); image = new File("src/test/resources/test-image.png"); MultipartFile mockImage = new MockMultipartFile("emptyImageFile", new byte[0]); given(storageService.uploadFile(mockImage, "path")) @@ -655,6 +671,7 @@ void setUp() { void should_uploadImageUrl_when_givenImageFile() { given(spec).log().all() .filter(document("upload-product-image-success", resource(successSnippets))) + .cookies(cookieProvider.createCookies()) .multiPart("image", image) .contentType(MediaType.MULTIPART_FORM_DATA_VALUE) .when().post("/offerings/product-images/s3")