forked from codesquad-members-2023/todo-max
-
Notifications
You must be signed in to change notification settings - Fork 1
Spring
JeeIn Lee edited this page Jul 24, 2023
·
2 revisions
-
Spring Filter
를 사용하여 로그인 기능 구현 - CORS는 Configuration으로 설정
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.
- CORS 에러가 날 거면 다 같이 나지 왜 따로 따로 나는가?
- 왜
preflight
요청은CORS
에러가 안 뜨고 본요청만CORS
에러가 발생하는가?
- 팀 프로젝트를 시작하기 전에 WAS 미션을 진행하며
Spring
구조에 대해 공부하면서 봤던 구조가 생각났다.
-
Filter
가Dispatcher Servlet
실행되기 전에 먼저 실행되니까WebMvcConfigurer
의 설정이 적용이 안되는 것 같다는 생각이 들었다.- 근데 왜 login 페이지 진입은 되는 것인지? 이해할 수가 없네...(답답) - 무튼 그래서 "
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);
}
}
- 1)번 상황이랑 동일
api 요청할 때 preflight
요청이 계속 발생하여 preflight
에 대해 공부하고 다시 Trouble Shooting 시작
-
preflight
요청은header
에authorization
헤더가 없어서 인증을 하지 못해401
에러가 발생하고, 이로 인해 본 요청에서 무슨 오류가 생긴게 아닐까 생각했다.
-
preflight
요청이401
이 발생했다는 것은CORS
는 통과한 것으로 이해된다.- 로그를 찍었을 때 Login Filter까지 들어온 것을 확인했기 때문이다.
- 로그를 찍었을 때 Login Filter까지 들어온 것을 확인했기 때문이다.
- 그러면 본요청도
CORS
에러가 나지 않아야 하는 것이 정상이 아닌가?- 본요청은
request
메시지를 파싱하는 순서가 다른가? - 예를 들면 header를 파싱하는 과정에서
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 에러에서 확인 가능하다.
Jinny Comment:
글을 작성하다가 문득 빈이 공유해주신 블로그 글을 다시 보면서
Filter
를 Bean
으로 설정하면 Spring
에서 Filter
를 관리해주니까
CorsFilter
를 구현하지 않고 처음 설정했던 WebMvcConfigure
를 설정해주면 먹히지 않을까라는 생각이 갑자기 들었다.