Spring Boot/Spring Security

[Spring Security] 예외 처리 및 요청 캐시 필터

수수한개발자 2022. 6. 29.
728x90

ExceptionTranslationFilter

ExceptionTranslationFilter는 두 가지 종류의 예외를 처리한다.

FilterSecurityinterceptor 필터가 맨 마지막 필터인데 이 필터 바로 앞에 위치한 필터가 ExceptionTranslationFilter입니다.

ExceptionTranslationFilter  가 실행될 때 try catch로 FilterSecurityinterceptor를 호출하고 있습니다.

AuthenticationException : 인증 예외 처리

 1. AuthenticationEntryPoint 호출

• 로그인 페이지 이동, 401 오류 코드 전달 등

      --사용자에게 인증 예외가 발생했기 때문에 다시금 인증을 할 수 있게 처리한다.

   --개발자가 구현하게 되면 구현한 클래스를 호출할 수 있다.

2. 인증 예외가 발생하기 전의 요청 정보를 저장

• RequestCache - 사용자의 이전 요청 정보를 세션에 저장하고 이를 꺼내 오는 캐시 메커니즘

• SavedRequest - 사용자가 요청했던 request 파라미터 값들, 그 당시의 헤더 값들 등이 저장

 

AccessDeniedException : 인가 예외 처리

  • AccessDeniedHandler에서 예외 처리하도록 제공한다.
  • 그 자원에 접근할 수 없다는 메시지 등을 전달할 수 있다.

이런 예외를 던져 주는 게 FilterSecurityInterceptor입니다. 

 

protected void configure(HttpSecurity http) throws Exception {
    http.exceptionHandling() 
    .authenticationEntryPoint(authenticationEntryPoint()) // 인증실패 시 처리
    .accessDeniedHandler(accessDeniedHandler()) // 인증실패 시 처리
}

 

http.exceptionHandling() : 예외 처리 기능이 작동합니다.

 . authenticationEntryPoint(authenticationEntryPoint()) // 인증 실패 예외 시 처리
  . accessDeniedHandler(accessDeniedHandler()) // 인가 예외  시 처리

 

적용 코드

http
                .authorizeRequests()
                .antMatchers("/login").permitAll()
                .antMatchers("/user").hasRole("USER")
                .antMatchers("/admin/pay").hasRole("ADMIN")
                .antMatchers("/admin/**").access("hasRole('ADMIN') or hasRole('SYS')")
                .anyRequest().authenticated();
        http
                .formLogin()
                .successHandler(new AuthenticationSuccessHandler() {
                    @Override
                    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                        RequestCache requestCache = new HttpSessionRequestCache();
                        SavedRequest savedRequest = requestCache.getRequest(request, response);//사용자가 접속하려는 url 정보가 담겨져 있음.
                        String redirectUrl = savedRequest.getRedirectUrl();
                        response.sendRedirect(redirectUrl);
                    }
                })
        ;
        http
                .exceptionHandling()
                .authenticationEntryPoint(new AuthenticationEntryPoint() {
                    @Override
                    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
                        response.sendRedirect("/login"); //우리가 만든 로그인 페이지로 이동한다.
                    }
                })
                .accessDeniedHandler(new AccessDeniedHandler() {
                    @Override
                    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
                        response.sendRedirect("/denied");
                    }
                });

첫 번째 http

에서 이 전 글과 동일한데 exception이 났을 때 우리가 만든 로그인 페이지로 이동하게끔 /login의 경로를 permitAll() 해줬습니다.

 

두 번째 http

는 인증을 성공했을 때의 성공 핸들러입니다. 사용자가 인증을 하기 전 요청했던 url정보를 가진 객체를 받아와서 인증 성공 후 그 url로 이동시켜주는 로직입니다.

http
        .formLogin()
        .successHandler(new AuthenticationSuccessHandler() {
            @Override
            public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                RequestCache requestCache = new HttpSessionRequestCache();
                SavedRequest savedRequest = requestCache.getRequest(request, response);//사용자가 접속하려는 url 정보가 담겨져 있음.
                String redirectUrl = savedRequest.getRedirectUrl();
                response.sendRedirect(redirectUrl);
            }
        })
;

 

 

 

세 번째 http

.authenticationEntryPoint(new AuthenticationEntryPoint() {
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        response.sendRedirect("/login"); //우리가 만든 로그인 페이지로 이동한다.
    }
})

이 코드는 인증 예외가 일어났을 때 예외처리를 하는 핸들러를 익명 클래스로 구현 해 놓은 것이다.

 

.accessDeniedHandler(new AccessDeniedHandler() {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
        response.sendRedirect("/denied");
    }
});

인가 예외를 했을 때 /denied라는 경로로 보내서 인가 예외처리를 한다.

728x90

댓글