일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 29 | 30 | 31 |
- 스프링 시큐리티
- 이터레이터
- 코드로배우는스프링부트웹프로젝트
- 처음 만나는 AI 수학 with Python
- 코드로배우는스프링웹프로젝트
- 스프링부트핵심가이드
- network configuration
- 페이징
- 리눅스
- iterator
- 목록처리
- 서버설정
- resttemplate
- 알파회계
- 자바편
- GIT
- 네트워크 설정
- /etc/network/interfaces
- Kernighan의 C언어 프로그래밍
- 구멍가게코딩단
- 자료구조와함께배우는알고리즘입문
- 친절한SQL튜닝
- d
- 자료구조와 함께 배우는 알고리즘 입문
- baeldung
- ㅒ
- 티스토리 쿠키 삭제
- 처음 만나는 AI수학 with Python
- 선형대수
- 데비안
- Today
- Total
bright jazz music
blog 27 : Interceptor 사용해 보기 본문
blog 26 포스팅에서 사용했던 get parameter, 또는 헤더 인증의 경우,
간단하게 값을 확인해서 if문으로 비교하여 api를 허용/거부처리 해줄 수 있었다.
0. 문제
그러나 이 방법의 경우 메소드가 추가될 때마다 동일한 작업을 반복하여 작성해야 한다는 단점이 있다. 매번 값을 꺼내고 확인하고, 인증값이 변경될 경우 모든 컨트롤러 메서드마다 변경해줘야 한다. 한 군데에서 한 번의 작업으로 전역적이고 반복적인 작업을 처리할 수 있는 방법이 필요하다.
1. 테스트 할 controller 생성하기
인터셉터는 요청이 컨트롤러 레이어에 진입하기 전에 공통된 작업을 해 준다. 인터셉터를 생성하기 전에 인터셉터를 테스트 할 핸들러를 생성하자.
//postController.java
@GetMapping("/test")
public String test(){ //인터셉터 테스트용
return "hello";
}
2. Interceptor 생성하고 로그 남겨보기
//AuthInterceptor.java
package com.endofma.blog.config;
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");
return true;
//만약 return false인 경우 컨트롤러까지 가지 않고 여기서 끝난다.
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
//postHandle : view반환 직후
log.info(">> postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
//afterCompletion : view반환 이후 모든 처리가 끝난 후
log.info(">> afterCompletion");
}
}
이후 재시작. 그러나 재시작해도 로그는 찍히지 않는다. WebMvcConfigurer에 생성한 인터셉터를 등록하지 않았기 때문이다.
3. WebMvcConfigurer를 구현한 클래스 생성
내 경우는 이미 존재했던 WebConfig파일을 WebMvcConfig로 이름만 변경해 주었다.
WebMvcConfigurer를 구현하게 한다. 그리고 클래스에 @Configuration 어노테이션을 붙여준다.
//WebMvcConfig.java
package com.endofma.blog.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
//인터셉터 추가
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new AuthInterceptor()); //생성한 인터셉터 등록
// .addPathPatterns() 적용할 패턴
// .excludePathPatterns() 제외할 패턴
}
//서버에서 CORS문제를 해결하는 방법
//frontend에서 Cors문제를 해결하는 실습을 위해 주석처리
//
// @Override
// public void addCorsMappings(CorsRegistry registry) {
// registry.addMapping("/**").allowedOrigins("http://localhost:5173");
// }
}
.addPathPatterns()는 해당 인터셉터에 적용한 작업을 적용할 패턴을 적어준다.
.excludePathPattern()은 제외할 패턴을 적어준다.
지금 처럼 패턴을 적용해 주지 않고 등록만 해줄 경우 모든 핸들러에 인터셉터의 작업을 적용한다.
4. preHandle() 변경 : 인증 로직 추가
//AuthInterceptor.java
package com.endofma.blog.config;
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값이 존재하고 catnails라면 true를 반환하여 접근 가능처리. 아니면 false 반환하여 거부
String accessToken = request.getParameter("accessToken");
if (accessToken != null && accessToken.equals("catnails")) {
return true;
}
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");
}
}
5. 인증 실패 및 인증이 필요하다는 예외를 json으로 반환해 주기
인증되지 않았다는 상태 코드 (401 unauthorized) 를 json으로 내려주기
5.1 Unauthorized 클래스 생성 후 내용 작성
Unauthorized.java 내용 작성
package com.endofma.blog.exception;
/**
* status > 401
*/
public class Unauthorized extends BlogException {
private static final String MESSAGE ="인증이 필요합니다.";
public Unauthorized() {
super(MESSAGE);
}
@Override
public int getStatusCode() {
return 401;
}
}
참고
//BlogException.java
package com.endofma.blog.exception;
import lombok.Getter;
import java.util.HashMap;
import java.util.Map;
@Getter
public abstract class BlogException extends RuntimeException{
//validation값 추가 위해 작성
public final Map<String, String> validation = new HashMap<>();
public BlogException(String message){
super(message);
}
public BlogException(String message, Throwable cause){
super(message, cause);
}
//추상메서드: 반드시 구현 필요
public abstract int getStatusCode();
public void addValidation(String fieldName, String message){
this.validation.put(fieldName, message);
}
}
5.2 AuthInterceptor 변경. Unathorized 객체를 false 대신 반환하도록 코드 수정
//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값이 존재하고 catnails라면 true를 반환하여 접근 가능처리. 아니면 false 반환하여 거부
String accessToken = request.getParameter("accessToken");
if (accessToken != null && accessToken.equals("catnails")) {
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");
}
}
6. 특정 API path를 인증에서 제외하기
.excludePathPattern() 적용
//PostController.java
@GetMapping("/foo")
public String foo(){
return "foo";
}
이 API path를 인터셉터에서의 작업에서 제외하고 싶은 경우 WebMvcConfigurer를 수정해 준다.
.excludePathPatterns()에 제외할 경로를 추가해 준다.
//WebMvcConfig.java
package com.endofma.blog.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
//인터셉터 추가
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new AuthInterceptor()) //생성한 인터셉터 등록
// .addPathPatterns() //인증 적용할 패턴
.excludePathPatterns("/foo"); //인증 제외할 패턴
}
}
이 설정은 설정한 패턴을아예 인터셉터의 작동에서 제외한다. 따라서 preHandle()의 ">>preHandle" 로그조차 남지 않는다. 인터셉터가 작동하지 않았기 때문이다.
이렇듯 컨트롤러 라우터마다 if문으로 처리하던 로직을 인터셉터에 적용해 줌으로써, 컨트롤러에 접근하기 전에 처리하도록 할 수 있다.
'Projects > blog' 카테고리의 다른 글
blog 29 : 헤더 인증으로 변경, Intellij http (0) | 2023.02.13 |
---|---|
blog 28 : ArgumentResolver 사용해보기 (0) | 2023.02.10 |
blog 26 : 가장 기본적인 요청 인증값 확인 (0) | 2023.02.08 |
blog 24 : 애플리케이션 프로세스 유지하기 (0) | 2023.02.08 |
blog21 : 배포 준비(빌드) (0) | 2023.02.06 |