인증 받지 않은 유저, 인가 받지 않은 유저를 필터링 하는 좋은 방법이 있어
글로 정리해보고자 한다.
글에서 나오는 SecurityConfig
클래스는 filterChain
메서드를 작성하는
Spring Security
의 환경 설정 클래스이다.
클래스명은 사람마다 다를 수 있다는 점을 알아주기 바란다.
사용 버전 정보
- Spring Boot: 3.4.1
- Spring Security: 6.4.2
- Java: 17
인증 받지 않은 유저를 처리할 수 있게 해주는 인터페이스가 존재한다.
바로 AuthenticationEntryPoint
라는 인터페이스다.
이 인터페이스를 구현하는 클래스를 만들어 Spring Security에 등록하면
인증 받지 않은 유저에 대한 예외 처리가 가능해진다.
ex) 응답 날리기, 리디렉션 하기 등
코드를 보며 예시를 살펴보자.
@Component
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write("{\"error\": \"Unauthorized\", \"message\": \"로그인이 필요합니다.\"}");
}
}
@Component
어노테이션을 사용하여 빈으로 등록했다.
이는 SecurityConfig
클래스에서 주입 받아 사용하려는 목적을 가진다.
AuthenticationEntryPoint
인터페이스를 구현하려면 commence
라는 메서드를 오버라이딩 해야된다.
나는 response
에 Content-Type, Encoding, status 설정을 하고 메세지를 작성해주었다.
이렇게 메서드 내용을 작성한 후 SecurityConfig
클래스에 등록해주면 된다.
등록하는 과정은 인가 관련 클래스를 작성 후 보여주겠다.
인가받지 않은 유저를 처리할 수 있게 해주는 인터페이스가 존재한다.
바로 AccessDeniedHandler
인터페이스다.
이 인터페이스도 마찬가지로 구현하는 클래스를 작성 후 SecurityConfig
클래스에 등록해주면
인가 받지 않은 유저에 대한 예외처리를 할 수 있게 된다.
@Component
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write("{\"error\": \"Unauthorized\", \"message\": \"권한이 없습니다.\"}");
}
}
이 클래스도 @Component
어노테이션을 사용해 빈으로 등록했다.
AccessDeniedHandler
인터페이스에는 구현해야할 handle
메서드가 존재한다.
해당 메서드 안에 인가 받지 않은 유저에 대한 처리를 작성하면 된다.
아까와 마찬가지로 response
에 여러 옵션을 설정해줬다.
이렇게 인증과 인가 관련 예외 처리 클래스 작성이 완료됐다.
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
private final CustomAuthenticationEntryPoint customAuthenticationEntryPoint;
private final CustomAccessDeniedHandler customAccessDeniedHandler;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// ~~생략~~
http
.exceptionHandling((exceptions) -> exceptions
.authenticationEntryPoint(customAuthenticationEntryPoint)
.accessDeniedHandler(customAccessDeniedHandler)
);
// ~~생략~~
return http.build();
}
}
SecurityConfig
클래스의 filterChain
메서드 안에 등록하면 된다.
HttpSecurity
객체가 갖는 exceptionHandling
메서드 안에 람다식을 작성하고
구현하는 인터페이스 명과 일치하는 메서드에 알맞은 객체를 전달해준다.
이렇게 하면 인증되지 않은 사용자가 접근하려할 때 혹은
인가받지 않은 사용자가 특정 자원에 접근하려할 때의 예외 처리가 가능해진다.
Oauth2 로그인을 구현하는 도중,
해당 클래스를 작성하기 전에는 인증 받지 않은 사용자가 접근했을 때
의도치 않게 로그인 페이지로 리다이렉션되는 어려움을 겪었다.
리다이렉션을 방지하고 메세지와 오류 상태코드를 반환하고자 사용하였다.
스프링 시큐리티의 편리함과 기능의 다양성을 느낄 수 있었던 좋은 경험이었다.