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일 뒤 새로 시작하는 팀프로젝트 때 꼭 확인해봐야겠다.