
Spring Security는 디폴트 설정이 클라이언트에게 SessionID로 인증할 수 있도록 리턴한다.
Session 방식이 아닌 토큰 방식, 그 중에 JWT로 인증할 수 있게 커스텀해보도록 한다.
Filter 는 DispatcherServlet 이전에 처리되는 Spring의 기능 중 하나이며 여러 Filter들이 존재할 수 있고 체이닝되는데, 그 중에 Spring Security 프레임워크는 SecurityFilterChain 이라는 체이닝되는 여러 필터들을 실행한다.
우리가 원하는 로직에 맞게 설정하려면 해당 필터들을 구현해서 오버라이딩 해주어야 한다.
구현하고자 하는 인증 방식이 ID-PW 방식의 로그인이라면 다음과 같이 정의해 본다.
// 로그인 인증(username-password) 방식 필터 사용자 정의
public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private final JwtUtil jwtUtil; // Jwt 토큰을 다루는 유틸 클래스 (사용자 정의 클래스)
public JwtAuthenticationFilter(JwtUtil jwtUtil) {
this.jwtUtil = jwtUtil;
setFilterProcessesUrl("/api/user/login"); // 0. 필터 적용할 URl 세팅
}
// 1. 로그인 시도할 때 실행되는 메서드
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
try {
LoginRequestDto requestDto = new ObjectMapper().readValue(request.getInputStream(), LoginRequestDto.class);
// getAuthenticationManager().authenticate() : 인증처리, 사용자 검증
return getAuthenticationManager().authenticate(
new UsernamePasswordAuthenticationToken(
requestDto.getUsername(),
requestDto.getPassword(),
null
)
);
} catch (IOException e) {
throw new RuntimeException(e.getMessage());
}
}
// 2. 로그인이 성공되었을 때 실행되는 메서드
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
String username = ((UserDetailsImpl) authResult.getPrincipal()).getUsername();
UserRoleEnum role = ((UserDetailsImpl) authResult.getPrincipal()).getUser().getRole();
String token = jwtUtil.createToken(username, role);
jwtUtil.addJwtToCookie(token, response);
}
// 3. 로그인 실패시 실행되는 메서드
@Override
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
response.setStatus(401);
}
}