Spring Filter를 사용하여 로그인 기능 구현보다 상세한 코드는 Gihub에서 확인 가능하다.
Configuration 코드
url, origin, method를 해용해준 상태@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("*")
.maxAge(3000);
}
}
Filter 코드
public class JwtAuthorizationFilter implements Filter {
// 생략
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws ServletException, IOException {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
// api의 화이트리스트 여부 체크
if(whiteListCheck(httpServletRequest.getRequestURI())){
chain.doFilter(request, response);
return;
}
// request header에 토큰 포함 여부 체크
if(!isContainToken(httpServletRequest)){
sendErrorApiResponse(response, new MalformedJwtException(""));
return;
}
// 필터 로직 진행
try {
String token = getToken(httpServletRequest);
Claims claims = jwtProvider.getClaims(token);
request.setAttribute("memberId", claims.get("memberId"));
chain.doFilter(request, response);
} catch (RuntimeException e) {
sendErrorApiResponse(response, e);
}
}
}
단계 별로 에러가 발생해서 단계별
Trouble Shooting과정을 정리했다.
POST 요청인 login은 CORS 에러가 발생하지 않는데,GET요청으로 메인 페이지(api/columns)로 리다이렉트되면서 CORS 에러 발생
Access to fetch at 'http://localhost:8080/api/columns' from origin 'http://localhost:5173' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
preflight 요청은 CORS 에러가 안 뜨고 본요청만 CORS 에러가 발생하는가?Spring 구조에 대해 공부하면서 봤던 구조가 생각났다.Filter가 Dispatcher Servlet 실행되기 전에 먼저 실행되니까 WebMvcConfigurer의 설정이 적용이 안되는 것 같다는 생각이 들었다.Login Filter 이전에 CORS Filter를 넣어주면 되지 않을까?"라는 생각이 들어 WebConfig를 삭제하고 CORS Filter를 추가했다.FilterConfig 코드
@Configuration
public class FilterConfig {
// 추가한 필터
@Bean
public FilterRegistrationBean corsFilter() {
FilterRegistrationBean<Filter> filterRegistrationBean = new FilterRegistrationBean<>();
filterRegistrationBean.setFilter(new CorsFilter());
filterRegistrationBean.setOrder(1); // 첫번째 순서로 넣어주기
return filterRegistrationBean;
}
// 기존 필터
@Bean
public FilterRegistrationBean jwtAuthorizationFilter(ObjectMapper mapper) {
FilterRegistrationBean<Filter> filterRegistrationBean = new
FilterRegistrationBean<>();
filterRegistrationBean.setFilter(new JwtAuthorizationFilter(mapper));
filterRegistrationBean.setOrder(2); // 순서 1에서 2로 변경
return filterRegistrationBean;
}
}
CorsFilter 코드
public class CorsFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException, IOException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, OPTIONS, GET, DELETE, PUT");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Authorization, x-requested-with, origin, content-type, accept");
chain.doFilter(req, res);
}
}
api 요청할 때 preflight 요청이 계속 발생하여 preflight에 대해 공부하고 다시 Trouble Shooting 시작
preflight 요청은 header에 authorization 헤더가 없어서 인증을 하지 못해 401 에러가 발생하고, 이로 인해 본 요청에서 무슨 오류가 생긴게 아닐까 생각했다.preflight 요청이 401이 발생했다는 것은 CORS는 통과한 것으로 이해된다.
CORS 에러가 나지 않아야 하는 것이 정상이 아닌가?request 메시지를 파싱하는 순서가 다른가? allow-origin header를 authorization header 보다 늦게 파싱해서? OPTIONS로 preflight 요청이 올 경우 필터 통과하는 코드 추가
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws ServletException, IOException {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
// OPTIONS로 api 요청 시 필터 통과
if (httpServletRequest.getMethod().equals("OPTIONS")) {
return;
}
// 이하 코드 생략...
// api의 화이트리스트 여부 체크
// request header에 토큰 포함 여부 체크
// 필터 로직 진행
}
CORS 에러는 없어졌지만 매우 찝찝하다.
Spring과 http 요청 흐름에 대한 지식을 더 쌓고 의문을 해결해야겠다.💡 참고:
401에러가 난 부분은 JWT 인증 관련 에러인데 해당 에러에 대한 Trouble Shooting 과정은 블로그 글 → [JWT] SignatureException 에러에서 확인 가능하다.
글을 작성하다가 문득 팀원이 공유해주신 블로그 글을 다시 보면서
Filter를 Bean으로 설정하면 Spring에서 Filter를 관리해주니까
CorsFilter를 구현하지 않고 처음 설정했던 WebMvcConfigure를 설정해주면 먹히지 않을까라는 생각이 갑자기 들었다.
지금은 팀프로젝트가 끝나 서버도 내려가고 당장 쌓인일이 많아서
3일 뒤 새로 시작하는 팀프로젝트 때 꼭 확인해봐야겠다.