일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- /etc/network/interfaces
- resttemplate
- iterator
- 리눅스
- 코드로배우는스프링부트웹프로젝트
- 자료구조와 함께 배우는 알고리즘 입문
- 네트워크 설정
- 친절한SQL튜닝
- GIT
- 자바편
- 알파회계
- 처음 만나는 AI수학 with Python
- 스프링 시큐리티
- 선형대수
- network configuration
- 티스토리 쿠키 삭제
- 이터레이터
- d
- ㅒ
- 처음 만나는 AI 수학 with Python
- 목록처리
- 페이징
- 서버설정
- 데비안
- baeldung
- Kernighan의 C언어 프로그래밍
- 코드로배우는스프링웹프로젝트
- 자료구조와함께배우는알고리즘입문
- 스프링부트핵심가이드
- 구멍가게코딩단
- Today
- Total
bright jazz music
blog 28 : ArgumentResolver 사용해보기 본문
AurgumentResolver:
preHandle에서 http 요청의 헤더를 검사한다.
request parameter에 key값이 "accessToken"인 값이 있으면 해당 값을 요청에 setAttribute 해준다.
이 때 key 값은 임의로 정해주어도 된다. 여기서는 "userName"을 key로, accessToken을 value로 넣어줬다.
여기서는 string 값을 넣어줬지만 object를 넘길 수도 있다.
request.setAttribute("userName", accessToken); <==멀티스레드 환경에서의 동작을 알아볼 필요가 있다.
//AuthInterceptor.java
package com.endofma.blog.config;
import com.endofma.blog.exception.Unauthorized;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Slf4j
public class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//prehandle : handler 가기 전에 작업
log.info(">> preHandle");
//accessToken값이 존재하고 ""이 아니라면 true를 반환하여 접근 가능처리. 아니면 false 반환하여 거부
String accessToken = request.getParameter("accessToken");
if (accessToken != null && !accessToken.equals("")) {
request.setAttribute("userName", accessToken);
return true;
}
throw new Unauthorized(); // 제이슨 반환
// return false;
// return accessToken.equals("catnails"); 이렇게 간소화 가능
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
//postHandle : handler 진입 이후
log.info(">> postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
//afterCompletion : view까지 처리가 끝난 후에 처리
log.info(">> afterCompletion");
}
}
//postController.java
@GetMapping("/foo")
public String foo(@RequestAttribute("userName") String userName ){
log.info(">>> {}", userName);
return "foo";
}
2. ArgumentResolver 생성하여 개선해보기
위와 같은 방식을 사용할 수도 있지만
ArgumentResolver를 사용해서 Controller의 파라마미터에서 임의로 만든 dto에 받아줄 수도 있다.
여기서는 AuthResolver라는 이름으로 생성했으며, 이 리졸버는 모든 요청에 대해 실행될 것이다.
//AuthResolver.java
package com.endofma.blog.config;
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.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
public class AuthResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
//컨트롤러에서 사용할 어노테이션이나 DTO가 사용자가 사용하려는 것이 맞는지, 지원하는지 체크한다.
return false;
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
//실제로 해당 DTO에 값을 세팅해준다.
return null;
}
}
3. ArgumentResolver 실습을 위해 DTO클래스를 생성하고 Controller 코드 변경
3.1 DTO 클래스 생성
//UserSession.java
package com.endofma.blog.config.data;
public class UserSession {
public String name;
}
UserSession 생성하기. 이 DTO는 PostController에서 argumentResolver를 실습하기 위해 사용한다.
3.2 컨트롤러 수정
//postController.java
@GetMapping("/foo")
public String foo(UserSession userSession){
log.info(">>> {}", userSession.name);
return "foo";
}
4. ArgumentResolver 내용 작성 01
우선은 사용하려는 클래스가 맞는지 확인하는 코드만 작성한다.
//AuthResolver.java
package com.endofma.blog.config;
import com.endofma.blog.config.data.UserSession;
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.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
public class AuthResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
//컨트롤러에서 사용할 어노테이션이나 DTO가 사용자가 사용하려는 것이 맞는지, 지원하는지 체크한다.
return parameter.getParameterType().equals(UserSession.class); //UserSession 클래스를 사용하는 것이 맞는지 확인. 맞으면 컨트롤러에 값 할당
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
//실제로 해당 DTO에 값을 세팅해준다. 추구 내용 작성 예정
return null;
}
}
5. WebMvcConfigurer에 ArgumentResolver 등록
//WebMvcConfig.java
package com.endofma.blog.config;
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;
import java.util.List;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
//인터셉터 추가
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new AuthInterceptor()) //생성한 인터셉터 등록
// .addPathPatterns() //인증 적용할 패턴
.excludePathPatterns("/error", "/favicon.ico"); //인증 제외할 패턴
}
@Override //인터셉터를 추가해줬듯이 아규먼트 리졸버를 추가해준다.
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new AuthResolver());
}
}
AuthResolver.java의
return parameter.getParameterType().equals(UserSession.class); 코드에 Break Point를 걸고
6. ArgumentResolver 내용 작성 02
resolveArgument() 메서드의 내용을 작성해준다.
아래에서는 userSession의 name에 catnails를 넣어줬다. 따라서 컨트롤러에서 catnails로그가 남아야 한다.
//AuthResolver.java
package com.endofma.blog.config;
import com.endofma.blog.config.data.UserSession;
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.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
public class AuthResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
//컨트롤러에서 사용할 어노테이션이나 DTO가 사용자가 사용하려는 것이 맞는지, 지원하는지 체크한다.
return parameter.getParameterType().equals(UserSession.class); //UserSession 클래스를 사용하는 것이 맞는지 확인. 맞으면 컨트롤러에 값 할당
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
//실제로 해당 DTO에 값을 세팅해준다.
UserSession userSession = new UserSession();
userSession.name = "catnails";
return userSession;
}
}
7. Interceptor 제거
API를 만들다 보면 인증이 필요한 라우터와 필요 없는 라우터가 갈리게 된다. 프로젝트가 커지면서 그 양은 더욱 많아진다. 따라서 일일이 인터셉터에 패턴 추가, 제외 해주는 작업은 번거로워진다.
우리가 만약 위에서 만든 UserSession 클래스처럼, 해당 객체가 포함된 API는 반드시 인증이 필요한 API라는 것을 알 수 있다. 왜냐하면 인증이 필요 없는데 굳이 인증이 필요한 객체를 파라미터에 사용할 필요는 없기 때문이다.
이러한 논리를 바탕으로 내가 생성한 AuthInterceptor 인터셉터를 WebMvcConfig에서 주석처리 할 것이다. 또한 인증처리를 ArgumentResolver에서 처리할 것이다.
//WebMvcConfig.java
package com.endofma.blog.config;
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;
import java.util.List;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
//인터셉터 추가
// @Override
// public void addInterceptors(InterceptorRegistry registry) {
// registry.addInterceptor(new AuthInterceptor()) //생성한 인터셉터 등록
//// .addPathPatterns() //인증 적용할 패턴
// .excludePathPatterns("/error", "/favicon.ico"); //인증 제외할 패턴
// }
@Override //인터셉터를 추가해줬듯이 아규먼트 리졸버를 추가해준다.
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new AuthResolver());
}
}
8. ArgumentResolver에 인증 로직 추가
//AuthResolver.java
package com.endofma.blog.config;
import com.endofma.blog.config.data.UserSession;
import com.endofma.blog.exception.Unauthorized;
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.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
public class AuthResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
//컨트롤러에서 사용할 어노테이션이나 DTO가 사용자가 사용하려는 것이 맞는지, 지원하는지 체크한다.
return parameter.getParameterType().equals(UserSession.class); //UserSession 클래스를 사용하는 것이 맞는지 확인. 맞으면 컨트롤러에 값 할당
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
//실제로 해당 DTO에 값을 세팅해준다.
//인증 작업 추가
String accessToken = webRequest.getParameter("accessToken");
if (accessToken == null || accessToken.equals("")) {
throw new Unauthorized();
}
UserSession userSession = new UserSession();
// userSession.name = "catnails";
userSession.name = accessToken;
return userSession;
}
}
현재는 값이 존재하는지 여부만 체크한다. 값이 존재하고 공백이 아니라면 무조건 통과. 값이 존재하지 않거나 있더라도 공백이라면 예외 발생
@GetMapping("/foo")
public String foo(UserSession userSession){
log.info(">>> {}", userSession.name);
return userSession.name;
}
이렇듯 파라미터 값에 UserSession 객체가 존재하면 아규먼트 리졸버의 인증 기능이 작동한다. 이는 supportParameter()에서 userSession.class가 파라미터에 존재하는지 확인하기 때문이다. 존재한다면 resolveArgument() 메서드에서 인증 기능을 수행한다.
@GetMapping("/bar")
public String bar(){
return "인증이 필요 없는 페이지";
}
만약 위와 같은 api가 있다면 accessToken 값을 넣어 요청하지 않아도 예외가 발생하지 않는다. "인증이 필요 없는 페이지"라는 문자열을 브라우저 창에서 볼 수 있을 것이다. 해당 api의 파라미터에 UserSession이 없기 때문이다.
인터셉터는 실무에서 생각보다 많이 쓰이지는 않는 듯하다.
'Projects > blog' 카테고리의 다른 글
blog 30 : 고정인증 로그인 기능 구현 1 (0) | 2023.02.14 |
---|---|
blog 29 : 헤더 인증으로 변경, Intellij http (0) | 2023.02.13 |
blog 27 : Interceptor 사용해 보기 (0) | 2023.02.09 |
blog 26 : 가장 기본적인 요청 인증값 확인 (0) | 2023.02.08 |
blog 24 : 애플리케이션 프로세스 유지하기 (0) | 2023.02.08 |