Skip to content

Commit

Permalink
Merge pull request #42 from inhooo00/feature/annotation
Browse files Browse the repository at this point in the history
 Feat(#29): 어노테이션 구현
  • Loading branch information
inhooo00 authored Jul 28, 2024
2 parents 86e935d + 444fdcc commit 0237e84
Show file tree
Hide file tree
Showing 5 changed files with 214 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package shop.kkeujeok.kkeujeokbackend.global.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface CurrentUserEmail {
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package shop.kkeujeok.kkeujeokbackend.global.annotationresolver;

import jakarta.servlet.http.HttpServletRequest;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import shop.kkeujeok.kkeujeokbackend.auth.api.dto.request.TokenReqDto;
import shop.kkeujeok.kkeujeokbackend.global.annotation.CurrentUserEmail;
import shop.kkeujeok.kkeujeokbackend.global.jwt.TokenProvider;

@Component
public class CurrentUserEmailArgumentResolver implements HandlerMethodArgumentResolver {

private final TokenProvider tokenProvider;

public CurrentUserEmailArgumentResolver(TokenProvider tokenProvider) {
this.tokenProvider = tokenProvider;
}

@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterAnnotation(CurrentUserEmail.class) != null;
//@CurrentUserEmail 어노테이션으로 주석되어 있는지 확인하는 로직.
}

@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {
HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest();
String token = request.getHeader("Authorization");

if (token != null && token.startsWith("Bearer ")) {
token = token.substring(7); // "Bearer " 이후의 토큰 부분만 추출하고
TokenReqDto tokenReqDto = new TokenReqDto(token);

return tokenProvider.getUserEmailFromToken(tokenReqDto); // 만들어둔 메서드로 email 값 반환
}

return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package shop.kkeujeok.kkeujeokbackend.global.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import shop.kkeujeok.kkeujeokbackend.global.annotationresolver.CurrentUserEmailArgumentResolver;

import java.util.List;

@Configuration
public class AnnotationWebConfig implements WebMvcConfigurer {

private final CurrentUserEmailArgumentResolver currentUserEmailArgumentResolver;

public AnnotationWebConfig(CurrentUserEmailArgumentResolver currentUserEmailArgumentResolver) {
this.currentUserEmailArgumentResolver = currentUserEmailArgumentResolver;
}

@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(currentUserEmailArgumentResolver);
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package shop.kkeujeok.kkeujeokbackend.global.config;

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import shop.kkeujeok.kkeujeokbackend.global.filter.LogFilter;
import shop.kkeujeok.kkeujeokbackend.global.filter.LoginCheckFilter;
import shop.kkeujeok.kkeujeokbackend.global.jwt.TokenProvider;

@Configuration
public class FilterWebConfig {
private final TokenProvider tokenProvider;

public FilterWebConfig(TokenProvider tokenProvider) {
this.tokenProvider = tokenProvider;
}

@Bean
public FilterRegistrationBean<LogFilter> logFilter() {
FilterRegistrationBean<LogFilter> filterRegistrationBean = new FilterRegistrationBean<>();
filterRegistrationBean.setFilter(new LogFilter()); // 여기서 만든 필터 클래스 등록
filterRegistrationBean.setOrder(1);
filterRegistrationBean.addUrlPatterns("/*");
return filterRegistrationBean;
}

@Bean
public FilterRegistrationBean<LoginCheckFilter> loginCheckFilter() {
FilterRegistrationBean<LoginCheckFilter> filterRegistrationBean = new FilterRegistrationBean<>();
filterRegistrationBean.setFilter(new LoginCheckFilter(tokenProvider)); // JWT 토큰 유효성 검사를 위한 필터 클래스 등록
filterRegistrationBean.setOrder(2); // 1번인 로그필터 다음으로 수행
filterRegistrationBean.addUrlPatterns("/*");
return filterRegistrationBean;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package shop.kkeujeok.kkeujeokbackend.global.annotationresolver;

import jakarta.servlet.http.HttpServletRequest;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.ModelAndViewContainer;
import shop.kkeujeok.kkeujeokbackend.auth.api.dto.request.TokenReqDto;
import shop.kkeujeok.kkeujeokbackend.global.annotation.CurrentUserEmail;
import shop.kkeujeok.kkeujeokbackend.global.jwt.TokenProvider;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

public class CurrentUserEmailArgumentResolverTest {

@Mock
private TokenProvider tokenProvider;

@Mock
private HttpServletRequest request;

@Mock
private NativeWebRequest webRequest;

@Mock
private MethodParameter methodParameter;

@InjectMocks
private CurrentUserEmailArgumentResolver resolver;

@BeforeEach
public void setUp() {
MockitoAnnotations.openMocks(this);
}
@DisplayName("어노테이션이 있을 때는 true를 반환하고, 없을 때는 false를 반환합니다.")
@Test
public void 어노테이션이_있을_때는_true를_반환하고_없을_때는_false를_반환합니다() {
when(methodParameter.getParameterAnnotation(CurrentUserEmail.class)).thenReturn(mock(CurrentUserEmail.class));
assertTrue(resolver.supportsParameter(methodParameter));

when(methodParameter.getParameterAnnotation(CurrentUserEmail.class)).thenReturn(null);
assertFalse(resolver.supportsParameter(methodParameter));
}

@DisplayName("토큰을 통해 이메일을 추출합니다.")
@Test
public void 토큰을_통해_이메일을_추출합니다() {
String token = "Bearer someValidToken";
String userEmail = "[email protected]";

when(webRequest.getNativeRequest()).thenReturn(request);
when(request.getHeader("Authorization")).thenReturn(token);
when(tokenProvider.getUserEmailFromToken(any(TokenReqDto.class))).thenReturn(userEmail);

Object result = resolver.resolveArgument(methodParameter,
mock(ModelAndViewContainer.class),
webRequest,
mock(WebDataBinderFactory.class));

assertEquals(userEmail, result);
}

@DisplayName("토큰이 없을 때 NULL을 호출합니다.")
@Test
public void 토큰이_없을_때_NULL을_호출합니다() {
when(webRequest.getNativeRequest()).thenReturn(request);
when(request.getHeader("Authorization")).thenReturn(null);

Object result = resolver.resolveArgument(methodParameter,
mock(ModelAndViewContainer.class),
webRequest,
mock(WebDataBinderFactory.class));

assertNull(result);
}

@DisplayName("토큰이 잘못됐을 때 NULL을 호출합니다.")
@Test
public void 토큰이_잘못됐을_때_NULL을_호출합니다() {
String token = "InvalidTokenFormat";

when(webRequest.getNativeRequest()).thenReturn(request);
when(request.getHeader("Authorization")).thenReturn(token);

Object result = resolver.resolveArgument(methodParameter,
mock(ModelAndViewContainer.class),
webRequest,
mock(WebDataBinderFactory.class));

assertNull(result);
}
}

0 comments on commit 0237e84

Please sign in to comment.