Skip to content

Commit

Permalink
Merge pull request #66 from Mu-necting/feat/#62
Browse files Browse the repository at this point in the history
액세스 토큰 유효성 검증 API 작성 완료
  • Loading branch information
mingmingmon authored Dec 9, 2024
2 parents 0fa29b3 + 7b39cea commit a5707f5
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@
import com.munecting.api.domain.user.dto.request.RefreshTokenRequestDto;
import com.munecting.api.domain.user.dto.request.LoginRequestDto;
import com.munecting.api.domain.user.dto.response.UserTokenResponseDto;
import com.munecting.api.domain.user.dto.response.ValidateTokenResponseDto;
import com.munecting.api.domain.user.service.AuthService;
import com.munecting.api.global.auth.user.UserId;
import com.munecting.api.global.common.dto.response.ApiResponse;
import com.munecting.api.global.common.dto.response.Status;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
Expand Down Expand Up @@ -56,7 +55,6 @@ public ApiResponse<?> logout(
return ApiResponse.ok(null);
}


@PostMapping("/refresh")
@Operation(summary = "토큰 재발급하기")
public ApiResponse<?> refreshToken(
Expand All @@ -65,4 +63,15 @@ public ApiResponse<?> refreshToken(
UserTokenResponseDto dto = authService.refreshToken(refreshTokenRequestDto);
return ApiResponse.created(dto);
}

@GetMapping("/validate")
@Operation(summary = "액세스 토큰 유효성 검증")
public ApiResponse<?> validateAccessToken(
@Parameter(hidden = true)
@RequestHeader("Authorization") String authorizationHeaderValue
){
ValidateTokenResponseDto dto = authService.validateAccessToken(authorizationHeaderValue);
return ApiResponse.ok(dto);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.munecting.api.domain.user.dto.response;

import lombok.Builder;

@Builder
public record ValidateTokenResponseDto(
boolean isValid
) {

public static ValidateTokenResponseDto of(boolean isValid) {
return ValidateTokenResponseDto.builder()
.isValid(isValid)
.build();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.munecting.api.domain.user.dto.request.RefreshTokenRequestDto;
import com.munecting.api.domain.user.dto.request.LoginRequestDto;
import com.munecting.api.domain.user.dto.response.UserTokenResponseDto;
import com.munecting.api.domain.user.dto.response.ValidateTokenResponseDto;
import com.munecting.api.domain.user.entity.User;
import com.munecting.api.domain.user.dao.UserRepository;
import com.munecting.api.global.auth.jwt.JwtProvider;
Expand Down Expand Up @@ -132,7 +133,7 @@ public void logout(LogoutRequestDto dto) {
}

private Long getUserIdFromAccessToken(String requestToken) {
String token = jwtProvider.extractAccessToken(requestToken);
String token = extractAccessToken(requestToken);

try {
jwtProvider.validateTokenAtLogout(token);
Expand All @@ -154,4 +155,21 @@ private void processLogout(Long userId) {
log.info("User {} logged out, no refresh token found", userId);
}
}

@Transactional(readOnly = true)
public ValidateTokenResponseDto validateAccessToken(String authorizationHeaderValue) {
try {
String accessToken = extractAccessToken(authorizationHeaderValue);
jwtProvider.validateAccessToken(accessToken);
return ValidateTokenResponseDto.of(true);
} catch (Exception e) {
log.info("Access token validation failed: {}", e.getMessage());
return ValidateTokenResponseDto.of(false);
}
}

private String extractAccessToken(String bearerToken) {
return jwtProvider.extractAccessToken(bearerToken);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import org.springframework.http.ResponseEntity;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingRequestHeaderException;
import org.springframework.web.bind.MissingRequestValueException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
Expand Down Expand Up @@ -73,15 +75,15 @@ protected ResponseEntity<ApiResponse<?>> handleConstraintViolationException(Cons
}

/**
* 필수 쿼리 파라미터를 누락한 경우 발생하는 error를 handling 합니다.
* 필수 쿼리 파라미터 & 헤더를 누락한 경우 발생하는 error를 handling 합니다.
*/
@ExceptionHandler(MissingServletRequestParameterException.class)
public ResponseEntity<ApiResponse<?>> handleMissingServletRequestParameterException(
MissingServletRequestParameterException e
@ExceptionHandler({MissingServletRequestParameterException.class, MissingRequestHeaderException.class})
public ResponseEntity<ApiResponse<?>> handleMissingRequestAttributes(
MissingRequestValueException e
) {
log.warn(">>> handle: MissingServletRequestParameterException", e);
log.warn(">>> handle: Missing required parameter or header Exception | [{}] - {}", e.getClass().getSimpleName(), e.getMessage());

ApiResponse<Object> response = ApiResponse.onFailure(BAD_REQUEST.toString(), e.getMessage(), null);
ApiResponse<Object> response = ApiResponse.onFailure(Status.BAD_REQUEST.getCode(), e.getMessage(), null);
return ResponseEntity.status(BAD_REQUEST).body(response);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.munecting.api.domain.user.service;

import com.munecting.api.domain.user.dto.response.ValidateTokenResponseDto;
import com.munecting.api.global.auth.jwt.JwtProvider;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class AuthServiceTest {

@Autowired
private AuthService authService;

@Autowired
private JwtProvider jwtProvider;

@DisplayName("주어진 액세스 토큰이 유효하면 true를 반환한다.")
@Test
public void validateAccessToken(){
//given
String accessToken = "Bearer " + jwtProvider.getIssueToken(1L, true);

//when
ValidateTokenResponseDto response = authService.validateAccessToken(accessToken);

//then
Assertions.assertThat(response.isValid()).isTrue();
}

@DisplayName("주어진 액세스 토큰이 유효하지 않으면 false를 반환한다.")
@Test
public void validateAccessToken_WithInValidToken(){
//given
String accessToken = "Bearer notVaild.아무값이나 넣었어.sdfhsodjf";

//when
ValidateTokenResponseDto response = authService.validateAccessToken(accessToken);

//then
Assertions.assertThat(response.isValid()).isFalse();
}

}

0 comments on commit a5707f5

Please sign in to comment.