시큐리티를 통해 접근할 수 있는 URI를 걸러내기 전에 JWT
를 통해서 해당 사용자를 인증해줘야한다. 그러기 위해서는 Filter Chain
에 등록되어 있는 Spring Security보다 먼저 검증을 해야한다.
그래서 JWT
를 만들어주는 필터를 만들어 볼 것이다.
우선 Filter 클래스를 만들어보고, 어떻게 동작하는지 살펴보자.
public class MyFilter1 implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("필터1");
chain.doFilter(request, response);
}
}
public class MyFilter2 implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("필터2");
chain.doFilter(request, response);
}
}
public class MyFilter3 implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("필터3");
chain.doFilter(request, response);
}
}
일단 3개의 필터를 만들었다.
필터를 만들었을 때 가장 주의할 점은 꼭 chain.doFilter()
를 호출해줘야 한다는 것이다.
만든 필터1, 2는 FilterConfig
클래스를 통해 등록해보고 필터3은 SecurityConfig
에 등록 시켜보자.
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean<MyFilter1> filter1() {
FilterRegistrationBean<MyFilter1> bean = new FilterRegistrationBean<>(new MyFilter1());
bean.addUrlPatterns("/*");
bean.setOrder(0);
return bean;
}
@Bean
public FilterRegistrationBean<MyFilter2> filter2() {
FilterRegistrationBean<MyFilter2> bean = new FilterRegistrationBean<>(new MyFilter2());
bean.addUrlPatterns("/*");
bean.setOrder(1);
return bean;
}
}
두 필터는 모든 URL호출에 작동될 것이고, 숫자가 작은 것부터 실행될 것이다.
필터3을 등록시켜 보자.
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
private final CorsFilter corsFilter;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
System.out.println("시큐리티 작동");
http.addFilterBefore(new MyFilter3(), BasicAuthenticationFilter.class);
(생략)
return http.build();
}
}
securityFilterChain
가 실행되기 전에 필터3이 실행된다.
이제 실행시켜 보면 다음과 같이 실행된다.
필터3
필터1
필터2
이런 식으로 실행된다.
필터1, 필터2는 그대로 냅두고 securityFilterChain
이 실행되기 전에 실행되는 필터3을 토큰을 만들고 인증하는 필터로 만들어 볼 것이다.
public class MyFilter3 implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
if (req.getMethod().equals("POST")) {
System.out.println("POST 요청됨");
String headerAuth = req.getHeader("Authorization");
System.out.println(headerAuth);
if (headerAuth.equals("cos")) {
chain.doFilter(request, response);
} else {
res.getWriter().write("인증안됨");
}
}
}
}
req.getHeader("Authorization)
에 값이 우리가 원하는 토큰값이면
chain.doFilter(request, response)
를 호출하여 컨트롤러까지 갈 수 있고,
우리가 원하는 토큰값이 아니면 "인증안됨"을 호출해준다는 의미이다.
클라이언트가 ID, PS를 정상적으로 넘겨주어 로그인이 완료되면 서버에서 토큰을 만들어주고 만든 토큰을 클라이언트에게 반환한다.
그 다음부터 클라이언트는 요청을 할 때마다 http header의 Authorization의 value값으로 토큰을 보낸다.
서버는 받은 토큰을 RSA or HS256을 통해 내가 만든 토큰이 맞는지 검증해주면 된다.