From e89039c3e6fc0b5498083d736bdcb07d0660a516 Mon Sep 17 00:00:00 2001 From: hseong3243 <48748265+hseong3243@users.noreply.github.com> Date: Wed, 8 Nov 2023 23:36:15 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EC=95=A1=EC=84=B8=EC=8A=A4=20=ED=86=A0?= =?UTF-8?q?=ED=81=B0=20=EC=A0=84=EC=86=A1=EC=8B=9C=20perfix=20Bearer?= =?UTF-8?q?=EB=A5=BC=20=EC=B6=94=EA=B0=80=ED=95=9C=EB=8B=A4.=20=20(#160)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 인증 패키지 구조를 개선한다. * feat: JWT 인증 필터에서 Bearer 를 명시한 토큰만을 받도록 변경한다. * docs: 인증 도메인 api 문서화를 추가한다. --- src/docs/asciidoc/index.adoc | 24 +++++++++++++++++++ .../animal/controller/AnimalController.java | 2 +- .../controller/ApplicantController.java | 2 +- .../domain/auth/{resolver => }/LoginUser.java | 2 +- .../JwtAuthenticationProvider.java | 2 +- .../auth/controller/AuthController.java | 6 ++--- .../request/LoginRequest.java | 2 +- .../{jwt => dto}/response/CustomClaims.java | 2 +- .../response/LoginResponse.java | 3 +-- .../{jwt => dto}/response/TokenResponse.java | 2 +- .../auth/exception/InvalidJwtException.java | 4 ++++ .../domain/auth/jwt/JwtProvider.java | 4 ++-- .../domain/auth/service/AuthService.java | 2 +- .../controller/RecruitmentController.java | 2 +- .../review/controller/ReviewController.java | 2 +- .../shelter/controller/ShelterController.java | 2 +- .../controller/VolunteerController.java | 2 +- .../global/config/SecurityConfig.java | 2 +- .../global/config/WebMvcConfig.java | 2 +- .../auth => global}/jwt/JJwtProvider.java | 15 ++++++------ .../LoginUserArgumentResolver.java | 3 ++- .../web}/filter/JwtAuthenticationFilter.java | 20 +++++++++++++--- .../JwtAuthenticationProviderTest.java | 2 +- .../auth/controller/AuthControllerTest.java | 6 ++--- .../filter/JwtAuthenticationFilterTest.java | 24 +++++++++++++++---- .../domain/auth/jwt/JJwtProviderTest.java | 5 ++-- .../resolver/LoginUserTestController.java | 1 + .../domain/auth/service/AuthServiceTest.java | 2 +- .../domain/auth/support/AuthFixture.java | 9 +++---- 29 files changed, 109 insertions(+), 47 deletions(-) rename src/main/java/com/clova/anifriends/domain/auth/{resolver => }/LoginUser.java (83%) rename src/main/java/com/clova/anifriends/domain/auth/{controller => dto}/request/LoginRequest.java (81%) rename src/main/java/com/clova/anifriends/domain/auth/{jwt => dto}/response/CustomClaims.java (81%) rename src/main/java/com/clova/anifriends/domain/auth/{controller => dto}/response/LoginResponse.java (73%) rename src/main/java/com/clova/anifriends/domain/auth/{jwt => dto}/response/TokenResponse.java (87%) rename src/main/java/com/clova/anifriends/{domain/auth => global}/jwt/JJwtProvider.java (91%) rename src/main/java/com/clova/anifriends/{domain/auth/resolver => global/web/argumentresolver}/LoginUserArgumentResolver.java (94%) rename src/main/java/com/clova/anifriends/{domain/auth => global/web}/filter/JwtAuthenticationFilter.java (60%) diff --git a/src/docs/asciidoc/index.adoc b/src/docs/asciidoc/index.adoc index 84030ff68..ea5ad864d 100644 --- a/src/docs/asciidoc/index.adoc +++ b/src/docs/asciidoc/index.adoc @@ -9,6 +9,30 @@ == 0. 인증 +=== 보호소 로그인 + +==== Request +operation::auth-controller-test/shelter-login[snippets='http-request,request-fields'] + +==== Response +operation::auth-controller-test/shelter-login[snippets='http-response,response-fields,response-cookies'] + +=== 봉사자 로그인 + +==== Request +operation::auth-controller-test/volunteer-login[snippets='http-request,request-fields'] + +==== Response +operation::auth-controller-test/volunteer-login[snippets='http-response,response-fields,response-cookies'] + +=== 액세스 토큰 갱신 + +==== Request +operation::auth-controller-test/refresh-access-token[snippets='http-request,request-cookies'] + +==== Response +operation::auth-controller-test/refresh-access-token[snippets='http-response,response-fields,response-cookies'] + == 1. 봉사자 === 봉사자가 완료한 봉사 모집글 리스트 조회 diff --git a/src/main/java/com/clova/anifriends/domain/animal/controller/AnimalController.java b/src/main/java/com/clova/anifriends/domain/animal/controller/AnimalController.java index 66d5cc258..92fecaf6d 100644 --- a/src/main/java/com/clova/anifriends/domain/animal/controller/AnimalController.java +++ b/src/main/java/com/clova/anifriends/domain/animal/controller/AnimalController.java @@ -8,7 +8,7 @@ import com.clova.anifriends.domain.animal.dto.response.FindAnimalsByVolunteerResponse; import com.clova.anifriends.domain.animal.dto.response.RegisterAnimalResponse; import com.clova.anifriends.domain.animal.service.AnimalService; -import com.clova.anifriends.domain.auth.resolver.LoginUser; +import com.clova.anifriends.domain.auth.LoginUser; import jakarta.validation.Valid; import java.net.URI; import lombok.RequiredArgsConstructor; diff --git a/src/main/java/com/clova/anifriends/domain/applicant/controller/ApplicantController.java b/src/main/java/com/clova/anifriends/domain/applicant/controller/ApplicantController.java index d23923b86..3cf2fd02e 100644 --- a/src/main/java/com/clova/anifriends/domain/applicant/controller/ApplicantController.java +++ b/src/main/java/com/clova/anifriends/domain/applicant/controller/ApplicantController.java @@ -3,7 +3,7 @@ import com.clova.anifriends.domain.applicant.dto.FindApplicantsApprovedResponse; import com.clova.anifriends.domain.applicant.dto.FindApplyingVolunteersResponse; import com.clova.anifriends.domain.applicant.service.ApplicantService; -import com.clova.anifriends.domain.auth.resolver.LoginUser; +import com.clova.anifriends.domain.auth.LoginUser; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; diff --git a/src/main/java/com/clova/anifriends/domain/auth/resolver/LoginUser.java b/src/main/java/com/clova/anifriends/domain/auth/LoginUser.java similarity index 83% rename from src/main/java/com/clova/anifriends/domain/auth/resolver/LoginUser.java rename to src/main/java/com/clova/anifriends/domain/auth/LoginUser.java index 47e52d3ba..50ffe2997 100644 --- a/src/main/java/com/clova/anifriends/domain/auth/resolver/LoginUser.java +++ b/src/main/java/com/clova/anifriends/domain/auth/LoginUser.java @@ -1,4 +1,4 @@ -package com.clova.anifriends.domain.auth.resolver; +package com.clova.anifriends.domain.auth; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/src/main/java/com/clova/anifriends/domain/auth/authentication/JwtAuthenticationProvider.java b/src/main/java/com/clova/anifriends/domain/auth/authentication/JwtAuthenticationProvider.java index 79bd876c7..7b9b4e148 100644 --- a/src/main/java/com/clova/anifriends/domain/auth/authentication/JwtAuthenticationProvider.java +++ b/src/main/java/com/clova/anifriends/domain/auth/authentication/JwtAuthenticationProvider.java @@ -1,7 +1,7 @@ package com.clova.anifriends.domain.auth.authentication; import com.clova.anifriends.domain.auth.jwt.JwtProvider; -import com.clova.anifriends.domain.auth.jwt.response.CustomClaims; +import com.clova.anifriends.domain.auth.dto.response.CustomClaims; import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; diff --git a/src/main/java/com/clova/anifriends/domain/auth/controller/AuthController.java b/src/main/java/com/clova/anifriends/domain/auth/controller/AuthController.java index 9b249accc..31512a295 100644 --- a/src/main/java/com/clova/anifriends/domain/auth/controller/AuthController.java +++ b/src/main/java/com/clova/anifriends/domain/auth/controller/AuthController.java @@ -1,8 +1,8 @@ package com.clova.anifriends.domain.auth.controller; -import com.clova.anifriends.domain.auth.controller.request.LoginRequest; -import com.clova.anifriends.domain.auth.controller.response.LoginResponse; -import com.clova.anifriends.domain.auth.jwt.response.TokenResponse; +import com.clova.anifriends.domain.auth.dto.request.LoginRequest; +import com.clova.anifriends.domain.auth.dto.response.LoginResponse; +import com.clova.anifriends.domain.auth.dto.response.TokenResponse; import com.clova.anifriends.domain.auth.service.AuthService; import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.Valid; diff --git a/src/main/java/com/clova/anifriends/domain/auth/controller/request/LoginRequest.java b/src/main/java/com/clova/anifriends/domain/auth/dto/request/LoginRequest.java similarity index 81% rename from src/main/java/com/clova/anifriends/domain/auth/controller/request/LoginRequest.java rename to src/main/java/com/clova/anifriends/domain/auth/dto/request/LoginRequest.java index c3d4a5557..b6df03425 100644 --- a/src/main/java/com/clova/anifriends/domain/auth/controller/request/LoginRequest.java +++ b/src/main/java/com/clova/anifriends/domain/auth/dto/request/LoginRequest.java @@ -1,4 +1,4 @@ -package com.clova.anifriends.domain.auth.controller.request; +package com.clova.anifriends.domain.auth.dto.request; import jakarta.validation.constraints.NotBlank; diff --git a/src/main/java/com/clova/anifriends/domain/auth/jwt/response/CustomClaims.java b/src/main/java/com/clova/anifriends/domain/auth/dto/response/CustomClaims.java similarity index 81% rename from src/main/java/com/clova/anifriends/domain/auth/jwt/response/CustomClaims.java rename to src/main/java/com/clova/anifriends/domain/auth/dto/response/CustomClaims.java index 93b2de397..171dae715 100644 --- a/src/main/java/com/clova/anifriends/domain/auth/jwt/response/CustomClaims.java +++ b/src/main/java/com/clova/anifriends/domain/auth/dto/response/CustomClaims.java @@ -1,4 +1,4 @@ -package com.clova.anifriends.domain.auth.jwt.response; +package com.clova.anifriends.domain.auth.dto.response; import java.util.List; diff --git a/src/main/java/com/clova/anifriends/domain/auth/controller/response/LoginResponse.java b/src/main/java/com/clova/anifriends/domain/auth/dto/response/LoginResponse.java similarity index 73% rename from src/main/java/com/clova/anifriends/domain/auth/controller/response/LoginResponse.java rename to src/main/java/com/clova/anifriends/domain/auth/dto/response/LoginResponse.java index 9c2cc1781..6b717b038 100644 --- a/src/main/java/com/clova/anifriends/domain/auth/controller/response/LoginResponse.java +++ b/src/main/java/com/clova/anifriends/domain/auth/dto/response/LoginResponse.java @@ -1,7 +1,6 @@ -package com.clova.anifriends.domain.auth.controller.response; +package com.clova.anifriends.domain.auth.dto.response; import com.clova.anifriends.domain.auth.jwt.UserRole; -import com.clova.anifriends.domain.auth.jwt.response.TokenResponse; public record LoginResponse(Long userId, UserRole role, String accessToken) { diff --git a/src/main/java/com/clova/anifriends/domain/auth/jwt/response/TokenResponse.java b/src/main/java/com/clova/anifriends/domain/auth/dto/response/TokenResponse.java similarity index 87% rename from src/main/java/com/clova/anifriends/domain/auth/jwt/response/TokenResponse.java rename to src/main/java/com/clova/anifriends/domain/auth/dto/response/TokenResponse.java index 495244369..a227263b3 100644 --- a/src/main/java/com/clova/anifriends/domain/auth/jwt/response/TokenResponse.java +++ b/src/main/java/com/clova/anifriends/domain/auth/dto/response/TokenResponse.java @@ -1,4 +1,4 @@ -package com.clova.anifriends.domain.auth.jwt.response; +package com.clova.anifriends.domain.auth.dto.response; import com.clova.anifriends.domain.auth.jwt.UserRole; diff --git a/src/main/java/com/clova/anifriends/domain/auth/exception/InvalidJwtException.java b/src/main/java/com/clova/anifriends/domain/auth/exception/InvalidJwtException.java index 06028448c..fd7373adf 100644 --- a/src/main/java/com/clova/anifriends/domain/auth/exception/InvalidJwtException.java +++ b/src/main/java/com/clova/anifriends/domain/auth/exception/InvalidJwtException.java @@ -5,6 +5,10 @@ public class InvalidJwtException extends AuthenticationException { + public InvalidJwtException(String message) { + super(ErrorCode.UN_AUTHENTICATION, message); + } + public InvalidJwtException(ErrorCode errorCode, String message) { super(errorCode, message); } diff --git a/src/main/java/com/clova/anifriends/domain/auth/jwt/JwtProvider.java b/src/main/java/com/clova/anifriends/domain/auth/jwt/JwtProvider.java index ec1511121..f1f07e738 100644 --- a/src/main/java/com/clova/anifriends/domain/auth/jwt/JwtProvider.java +++ b/src/main/java/com/clova/anifriends/domain/auth/jwt/JwtProvider.java @@ -1,8 +1,8 @@ package com.clova.anifriends.domain.auth.jwt; -import com.clova.anifriends.domain.auth.jwt.response.CustomClaims; -import com.clova.anifriends.domain.auth.jwt.response.TokenResponse; +import com.clova.anifriends.domain.auth.dto.response.CustomClaims; +import com.clova.anifriends.domain.auth.dto.response.TokenResponse; public interface JwtProvider { diff --git a/src/main/java/com/clova/anifriends/domain/auth/service/AuthService.java b/src/main/java/com/clova/anifriends/domain/auth/service/AuthService.java index 5bc7673d4..603400dfc 100644 --- a/src/main/java/com/clova/anifriends/domain/auth/service/AuthService.java +++ b/src/main/java/com/clova/anifriends/domain/auth/service/AuthService.java @@ -7,7 +7,7 @@ import com.clova.anifriends.domain.auth.exception.AuthNotFoundException; import com.clova.anifriends.domain.auth.jwt.JwtProvider; import com.clova.anifriends.domain.auth.jwt.UserRole; -import com.clova.anifriends.domain.auth.jwt.response.TokenResponse; +import com.clova.anifriends.domain.auth.dto.response.TokenResponse; import com.clova.anifriends.domain.auth.repository.RefreshTokenRepository; import com.clova.anifriends.domain.shelter.Shelter; import com.clova.anifriends.domain.shelter.repository.ShelterRepository; diff --git a/src/main/java/com/clova/anifriends/domain/recruitment/controller/RecruitmentController.java b/src/main/java/com/clova/anifriends/domain/recruitment/controller/RecruitmentController.java index 8f637ed83..4e4a0a8ff 100644 --- a/src/main/java/com/clova/anifriends/domain/recruitment/controller/RecruitmentController.java +++ b/src/main/java/com/clova/anifriends/domain/recruitment/controller/RecruitmentController.java @@ -1,6 +1,6 @@ package com.clova.anifriends.domain.recruitment.controller; -import com.clova.anifriends.domain.auth.resolver.LoginUser; +import com.clova.anifriends.domain.auth.LoginUser; import com.clova.anifriends.domain.recruitment.dto.request.FindRecruitmentsByShelterRequest; import com.clova.anifriends.domain.recruitment.dto.request.FindRecruitmentsByVolunteerRequest; import com.clova.anifriends.domain.recruitment.dto.request.RegisterRecruitmentRequest; diff --git a/src/main/java/com/clova/anifriends/domain/review/controller/ReviewController.java b/src/main/java/com/clova/anifriends/domain/review/controller/ReviewController.java index fe8a4e258..50eb30af4 100644 --- a/src/main/java/com/clova/anifriends/domain/review/controller/ReviewController.java +++ b/src/main/java/com/clova/anifriends/domain/review/controller/ReviewController.java @@ -1,6 +1,6 @@ package com.clova.anifriends.domain.review.controller; -import com.clova.anifriends.domain.auth.resolver.LoginUser; +import com.clova.anifriends.domain.auth.LoginUser; import com.clova.anifriends.domain.review.dto.request.RegisterReviewRequest; import com.clova.anifriends.domain.review.dto.response.FindReviewResponse; import com.clova.anifriends.domain.review.dto.response.FindShelterReviewsByVolunteerResponse; diff --git a/src/main/java/com/clova/anifriends/domain/shelter/controller/ShelterController.java b/src/main/java/com/clova/anifriends/domain/shelter/controller/ShelterController.java index 8a7755663..2a8dd699b 100644 --- a/src/main/java/com/clova/anifriends/domain/shelter/controller/ShelterController.java +++ b/src/main/java/com/clova/anifriends/domain/shelter/controller/ShelterController.java @@ -1,6 +1,6 @@ package com.clova.anifriends.domain.shelter.controller; -import com.clova.anifriends.domain.auth.resolver.LoginUser; +import com.clova.anifriends.domain.auth.LoginUser; import com.clova.anifriends.domain.shelter.dto.CheckDuplicateShelterEmailRequest; import com.clova.anifriends.domain.shelter.dto.CheckDuplicateShelterResponse; import com.clova.anifriends.domain.shelter.dto.FindShelterDetailResponse; diff --git a/src/main/java/com/clova/anifriends/domain/volunteer/controller/VolunteerController.java b/src/main/java/com/clova/anifriends/domain/volunteer/controller/VolunteerController.java index d81b8e3ad..5b6ad8547 100644 --- a/src/main/java/com/clova/anifriends/domain/volunteer/controller/VolunteerController.java +++ b/src/main/java/com/clova/anifriends/domain/volunteer/controller/VolunteerController.java @@ -1,6 +1,6 @@ package com.clova.anifriends.domain.volunteer.controller; -import com.clova.anifriends.domain.auth.resolver.LoginUser; +import com.clova.anifriends.domain.auth.LoginUser; import com.clova.anifriends.domain.volunteer.dto.request.CheckDuplicateVolunteerEmailRequest; import com.clova.anifriends.domain.volunteer.dto.request.RegisterVolunteerRequest; import com.clova.anifriends.domain.volunteer.dto.response.CheckDuplicateVolunteerEmailResponse; diff --git a/src/main/java/com/clova/anifriends/global/config/SecurityConfig.java b/src/main/java/com/clova/anifriends/global/config/SecurityConfig.java index 2e5f8689d..61674a3ad 100644 --- a/src/main/java/com/clova/anifriends/global/config/SecurityConfig.java +++ b/src/main/java/com/clova/anifriends/global/config/SecurityConfig.java @@ -1,7 +1,7 @@ package com.clova.anifriends.global.config; import com.clova.anifriends.domain.auth.authentication.JwtAuthenticationProvider; -import com.clova.anifriends.domain.auth.filter.JwtAuthenticationFilter; +import com.clova.anifriends.global.web.filter.JwtAuthenticationFilter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; diff --git a/src/main/java/com/clova/anifriends/global/config/WebMvcConfig.java b/src/main/java/com/clova/anifriends/global/config/WebMvcConfig.java index 761bf7ed9..d6cbc8862 100644 --- a/src/main/java/com/clova/anifriends/global/config/WebMvcConfig.java +++ b/src/main/java/com/clova/anifriends/global/config/WebMvcConfig.java @@ -1,6 +1,6 @@ package com.clova.anifriends.global.config; -import com.clova.anifriends.domain.auth.resolver.LoginUserArgumentResolver; +import com.clova.anifriends.global.web.argumentresolver.LoginUserArgumentResolver; import java.util.List; import org.springframework.context.annotation.Configuration; import org.springframework.web.method.support.HandlerMethodArgumentResolver; diff --git a/src/main/java/com/clova/anifriends/domain/auth/jwt/JJwtProvider.java b/src/main/java/com/clova/anifriends/global/jwt/JJwtProvider.java similarity index 91% rename from src/main/java/com/clova/anifriends/domain/auth/jwt/JJwtProvider.java rename to src/main/java/com/clova/anifriends/global/jwt/JJwtProvider.java index 30654734d..9a4e918d5 100644 --- a/src/main/java/com/clova/anifriends/domain/auth/jwt/JJwtProvider.java +++ b/src/main/java/com/clova/anifriends/global/jwt/JJwtProvider.java @@ -1,11 +1,12 @@ -package com.clova.anifriends.domain.auth.jwt; +package com.clova.anifriends.global.jwt; +import com.clova.anifriends.domain.auth.dto.response.CustomClaims; +import com.clova.anifriends.domain.auth.dto.response.TokenResponse; import com.clova.anifriends.domain.auth.exception.ExpiredAccessTokenException; -import com.clova.anifriends.domain.auth.exception.InvalidJwtException; import com.clova.anifriends.domain.auth.exception.ExpiredRefreshTokenException; -import com.clova.anifriends.domain.auth.jwt.response.CustomClaims; -import com.clova.anifriends.domain.auth.jwt.response.TokenResponse; -import com.clova.anifriends.global.exception.ErrorCode; +import com.clova.anifriends.domain.auth.exception.InvalidJwtException; +import com.clova.anifriends.domain.auth.jwt.JwtProvider; +import com.clova.anifriends.domain.auth.jwt.UserRole; import io.jsonwebtoken.Claims; import io.jsonwebtoken.ExpiredJwtException; import io.jsonwebtoken.JwtException; @@ -101,7 +102,7 @@ public CustomClaims parseAccessToken(String token) { } catch (JwtException ex) { log.info("[EX] {}: 잘못된 JWT입니다.", ex.getClass().getSimpleName()); } - throw new InvalidJwtException(ErrorCode.UN_AUTHENTICATION, "유효하지 않은 JWT입니다."); + throw new InvalidJwtException("유효하지 않은 JWT입니다."); } @Override @@ -117,6 +118,6 @@ public TokenResponse refreshAccessToken(String refreshToken) { } catch (JwtException ex) { log.info("[EX] {}: 잘못된 리프레시 토큰입니다.", ex.getClass().getSimpleName()); } - throw new InvalidJwtException(ErrorCode.UN_AUTHENTICATION, "유효하지 않은 리프레시 토큰입니다."); + throw new InvalidJwtException("유효하지 않은 리프레시 토큰입니다."); } } diff --git a/src/main/java/com/clova/anifriends/domain/auth/resolver/LoginUserArgumentResolver.java b/src/main/java/com/clova/anifriends/global/web/argumentresolver/LoginUserArgumentResolver.java similarity index 94% rename from src/main/java/com/clova/anifriends/domain/auth/resolver/LoginUserArgumentResolver.java rename to src/main/java/com/clova/anifriends/global/web/argumentresolver/LoginUserArgumentResolver.java index 61489dab3..bc29b6147 100644 --- a/src/main/java/com/clova/anifriends/domain/auth/resolver/LoginUserArgumentResolver.java +++ b/src/main/java/com/clova/anifriends/global/web/argumentresolver/LoginUserArgumentResolver.java @@ -1,9 +1,10 @@ -package com.clova.anifriends.domain.auth.resolver; +package com.clova.anifriends.global.web.argumentresolver; import static com.clova.anifriends.global.exception.ErrorCode.UN_AUTHENTICATION; import com.clova.anifriends.domain.auth.authentication.JwtAuthentication; import com.clova.anifriends.domain.auth.exception.AuthAuthenticationException; +import com.clova.anifriends.domain.auth.LoginUser; import java.util.Objects; import org.springframework.core.MethodParameter; import org.springframework.security.core.Authentication; diff --git a/src/main/java/com/clova/anifriends/domain/auth/filter/JwtAuthenticationFilter.java b/src/main/java/com/clova/anifriends/global/web/filter/JwtAuthenticationFilter.java similarity index 60% rename from src/main/java/com/clova/anifriends/domain/auth/filter/JwtAuthenticationFilter.java rename to src/main/java/com/clova/anifriends/global/web/filter/JwtAuthenticationFilter.java index 43d7a3f25..72c609f27 100644 --- a/src/main/java/com/clova/anifriends/domain/auth/filter/JwtAuthenticationFilter.java +++ b/src/main/java/com/clova/anifriends/global/web/filter/JwtAuthenticationFilter.java @@ -1,6 +1,7 @@ -package com.clova.anifriends.domain.auth.filter; +package com.clova.anifriends.global.web.filter; import com.clova.anifriends.domain.auth.authentication.JwtAuthenticationProvider; +import com.clova.anifriends.domain.auth.exception.InvalidJwtException; import jakarta.servlet.FilterChain; import jakarta.servlet.GenericFilter; import jakarta.servlet.ServletException; @@ -17,17 +18,30 @@ public class JwtAuthenticationFilter extends GenericFilter { private static final String HEADER = "Authorization"; + private static final String BEARER = "Bearer "; private final JwtAuthenticationProvider authenticationProvider; @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; - String accessToken = request.getHeader(HEADER); - if (Objects.nonNull(accessToken)) { + String bearerAccessToken = request.getHeader(HEADER); + if (Objects.nonNull(bearerAccessToken)) { + String accessToken = removeBearer(bearerAccessToken); Authentication authentication = authenticationProvider.authenticate(accessToken); SecurityContextHolder.getContext().setAuthentication(authentication); } chain.doFilter(req, res); } + + private String removeBearer(String bearerAccessToken) { + checkTokenContainsBearer(bearerAccessToken); + return bearerAccessToken.replace(BEARER, ""); + } + + private static void checkTokenContainsBearer(String bearerAccessToken) { + if(!bearerAccessToken.contains(BEARER)) { + throw new InvalidJwtException("올바르지 않는 액세스 토큰 형식입니다."); + } + } } diff --git a/src/test/java/com/clova/anifriends/domain/auth/authentication/JwtAuthenticationProviderTest.java b/src/test/java/com/clova/anifriends/domain/auth/authentication/JwtAuthenticationProviderTest.java index 6b64abf8a..31494952f 100644 --- a/src/test/java/com/clova/anifriends/domain/auth/authentication/JwtAuthenticationProviderTest.java +++ b/src/test/java/com/clova/anifriends/domain/auth/authentication/JwtAuthenticationProviderTest.java @@ -4,7 +4,7 @@ import com.clova.anifriends.domain.auth.jwt.JwtProvider; import com.clova.anifriends.domain.auth.jwt.UserRole; -import com.clova.anifriends.domain.auth.jwt.response.TokenResponse; +import com.clova.anifriends.domain.auth.dto.response.TokenResponse; import com.clova.anifriends.domain.auth.support.AuthFixture; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; diff --git a/src/test/java/com/clova/anifriends/domain/auth/controller/AuthControllerTest.java b/src/test/java/com/clova/anifriends/domain/auth/controller/AuthControllerTest.java index 548c5fcff..96a1c5366 100644 --- a/src/test/java/com/clova/anifriends/domain/auth/controller/AuthControllerTest.java +++ b/src/test/java/com/clova/anifriends/domain/auth/controller/AuthControllerTest.java @@ -15,9 +15,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.clova.anifriends.base.BaseControllerTest; -import com.clova.anifriends.domain.auth.controller.request.LoginRequest; +import com.clova.anifriends.domain.auth.dto.request.LoginRequest; import com.clova.anifriends.domain.auth.jwt.UserRole; -import com.clova.anifriends.domain.auth.jwt.response.TokenResponse; +import com.clova.anifriends.domain.auth.dto.response.TokenResponse; import com.clova.anifriends.domain.auth.support.AuthFixture; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -65,7 +65,7 @@ void volunteerLogin() throws Exception { void shelterLogin() throws Exception { //given LoginRequest request = new LoginRequest("email@email.com", "password123!"); - TokenResponse response = new TokenResponse(1L, UserRole.ROLE_VOLUNTEER, "accessToken", + TokenResponse response = new TokenResponse(1L, UserRole.ROLE_SHELTER, "accessToken", "refreshToken"); given(authService.shelterLogin(any(), any())).willReturn(response); diff --git a/src/test/java/com/clova/anifriends/domain/auth/filter/JwtAuthenticationFilterTest.java b/src/test/java/com/clova/anifriends/domain/auth/filter/JwtAuthenticationFilterTest.java index a0a8d0ce2..4d2c15380 100644 --- a/src/test/java/com/clova/anifriends/domain/auth/filter/JwtAuthenticationFilterTest.java +++ b/src/test/java/com/clova/anifriends/domain/auth/filter/JwtAuthenticationFilterTest.java @@ -1,14 +1,15 @@ package com.clova.anifriends.domain.auth.filter; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchException; import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.then; import com.clova.anifriends.domain.auth.authentication.JwtAuthenticationProvider; +import com.clova.anifriends.domain.auth.exception.InvalidJwtException; import com.clova.anifriends.domain.auth.jwt.JwtProvider; -import com.clova.anifriends.domain.auth.jwt.UserRole; -import com.clova.anifriends.domain.auth.jwt.response.TokenResponse; import com.clova.anifriends.domain.auth.support.AuthFixture; +import com.clova.anifriends.global.web.filter.JwtAuthenticationFilter; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import java.io.IOException; @@ -57,8 +58,7 @@ void doFilter() throws ServletException, IOException { @DisplayName("성공: 액세스 토큰이 요청에 포함된 경우") void doFilterWhenContainsToken() throws ServletException, IOException { //given - TokenResponse tokenResponse = jwtProvider.createToken(1L, UserRole.ROLE_VOLUNTEER); - String accessToken = tokenResponse.accessToken(); + String accessToken = AuthFixture.shelterAccessToken(); mockRequest.addHeader("Authorization", accessToken); //when @@ -80,5 +80,21 @@ void doFilterWhenNotContainsToken() throws ServletException, IOException { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); assertThat(authentication).isNull(); } + + @Test + @DisplayName("예외: 액세스 토큰이 Bearer 형식이 아닌 경우") + void exceptionWhenTokenIsNotBearer() { + //given + String bearerAccessToken = AuthFixture.volunteerAccessToken(); + String accessToken = bearerAccessToken.replace("Bearer ", ""); + mockRequest.addHeader("Authorization", accessToken); + + //when + Exception exception = catchException( + () -> jwtAuthenticationFilter.doFilter(mockRequest, mockResponse, filterChain)); + + //then + assertThat(exception).isInstanceOf(InvalidJwtException.class); + } } } diff --git a/src/test/java/com/clova/anifriends/domain/auth/jwt/JJwtProviderTest.java b/src/test/java/com/clova/anifriends/domain/auth/jwt/JJwtProviderTest.java index 2486bbaf6..e12150df1 100644 --- a/src/test/java/com/clova/anifriends/domain/auth/jwt/JJwtProviderTest.java +++ b/src/test/java/com/clova/anifriends/domain/auth/jwt/JJwtProviderTest.java @@ -7,9 +7,10 @@ import com.clova.anifriends.domain.auth.exception.ExpiredAccessTokenException; import com.clova.anifriends.domain.auth.exception.ExpiredRefreshTokenException; import com.clova.anifriends.domain.auth.exception.InvalidJwtException; -import com.clova.anifriends.domain.auth.jwt.response.CustomClaims; -import com.clova.anifriends.domain.auth.jwt.response.TokenResponse; +import com.clova.anifriends.domain.auth.dto.response.CustomClaims; +import com.clova.anifriends.domain.auth.dto.response.TokenResponse; import com.clova.anifriends.domain.auth.support.AuthFixture; +import com.clova.anifriends.global.jwt.JJwtProvider; import java.util.List; import java.util.concurrent.TimeUnit; import org.awaitility.core.ThrowingRunnable; diff --git a/src/test/java/com/clova/anifriends/domain/auth/resolver/LoginUserTestController.java b/src/test/java/com/clova/anifriends/domain/auth/resolver/LoginUserTestController.java index 78d270b4d..b127775a3 100644 --- a/src/test/java/com/clova/anifriends/domain/auth/resolver/LoginUserTestController.java +++ b/src/test/java/com/clova/anifriends/domain/auth/resolver/LoginUserTestController.java @@ -1,5 +1,6 @@ package com.clova.anifriends.domain.auth.resolver; +import com.clova.anifriends.domain.auth.LoginUser; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; diff --git a/src/test/java/com/clova/anifriends/domain/auth/service/AuthServiceTest.java b/src/test/java/com/clova/anifriends/domain/auth/service/AuthServiceTest.java index ca25c1a56..2d1daf313 100644 --- a/src/test/java/com/clova/anifriends/domain/auth/service/AuthServiceTest.java +++ b/src/test/java/com/clova/anifriends/domain/auth/service/AuthServiceTest.java @@ -12,7 +12,7 @@ import com.clova.anifriends.domain.auth.exception.AuthNotFoundException; import com.clova.anifriends.domain.auth.jwt.JwtProvider; import com.clova.anifriends.domain.auth.jwt.UserRole; -import com.clova.anifriends.domain.auth.jwt.response.TokenResponse; +import com.clova.anifriends.domain.auth.dto.response.TokenResponse; import com.clova.anifriends.domain.auth.repository.RefreshTokenRepository; import com.clova.anifriends.domain.auth.support.AuthFixture; import com.clova.anifriends.domain.auth.support.MockPasswordEncode; diff --git a/src/test/java/com/clova/anifriends/domain/auth/support/AuthFixture.java b/src/test/java/com/clova/anifriends/domain/auth/support/AuthFixture.java index 7e15e0dfb..73075ec44 100644 --- a/src/test/java/com/clova/anifriends/domain/auth/support/AuthFixture.java +++ b/src/test/java/com/clova/anifriends/domain/auth/support/AuthFixture.java @@ -1,9 +1,9 @@ package com.clova.anifriends.domain.auth.support; -import com.clova.anifriends.domain.auth.jwt.JJwtProvider; +import com.clova.anifriends.global.jwt.JJwtProvider; import com.clova.anifriends.domain.auth.jwt.JwtProvider; import com.clova.anifriends.domain.auth.jwt.UserRole; -import com.clova.anifriends.domain.auth.jwt.response.TokenResponse; +import com.clova.anifriends.domain.auth.dto.response.TokenResponse; public final class AuthFixture { @@ -14,6 +14,7 @@ public final class AuthFixture { private static final String TEST_REFRESH_SECRET = "~GWW.|?:\"#Rqmm^-nk#>#4Ngc}]3xz!hOQCXNF:8z-Mdn\"U!Vt