JAVA/Java

인증 예외 처리 문제 해결 (2) - Spring Security의 인증 / 인가 예외 처리

dodop 2023. 8. 21. 22:54

 

 

 

 

(지난 편,,,)

 

https://dodop-blog.tistory.com/447

 

AuthenticationEntryPoint와 ControllerAdvice

최근에 sprign security를 이용한 인증 처리 과정을 구현하다가 리더님께 다음의 코드에서 예외처리가 예상한대로 동작하지 않을 것이라는 리뷰를 받았다. 내가 구현한 예외처리 코드를 예시로 보

dodop-blog.tistory.com

지난 편에서는 Filter에서 발생한 예외는 이를 처리하는 또 다른 Filter를 구현하여 예외를 처리할 수 있다고 하였다.

그런데, 이번에 발생한 문제는 Filter구현이 아닌 AuthenticationEntryPoint 구현만으로 원하는 에외 처리를 할 수 있었다.

 

 

 

 

어떻게 된 걸까?

 

 

 

 

 

이와 관련해서 Spring Security에서 발생하는 예외와 이에 대한 처리 방법을 알아보자.

 

 

 

 

 

Spring Security 예외

출처 https://coder-in-war.tistory.com/entry/Spring-Security-05-%EC%9D%B8%EC%A6%9D%EC%9D%B8%EA%B0%80-API%EC%9D%98-%EC%98%88%EC%99%B8%EC%B2%98%EB%A6%AC (인프런 강의 정리)

먼저, Spring Security에서 발생할 수 있는 대표적인 예외에는 인증 예외와 인가 예외가 있다.

  • 인증 예외
    • AuthenticationException
    • 인증에 실패하는 경우에 발생
    • SpringContextHolder에 authentication 정보가 없으면 예외 발생
    • Spring Security 설정에서 다음과 같은 설정에서 발생할 수 있음 (인증된 사용자만 받는 경우)
.authorizeRequests()
  • 인가 예외
    • AccessDeniedException
    • 인가에 실패하는 경우에 발생
    • Spring Security 설정에서 다음과 같은 설정에서 발생할 수 있음 (특정 Role을 가진 사용자만 허용하는 경우)
.anyRequest().hasAnyRole(Role.ADMIN)

 

 

 

그렇다면 SpringSecurity에서 발생시키는 예외는 어떻게 처리할 수 있을까?

 

 

 

 

 

Spring Security 인증 / 인가 예외 처리

Spring Security에서 인증 / 인가 예외 처리를 담당하는 필터에는 FilterSecurityInterceptorExceptionTranslationFilter가 있다.

  • FilterSecurityInterceptor
    • 마지막 순서에 실행되는 필터
    • 인증된 사용자의 요청에 대한 권한처리를 담당
    • 인증 문제를 발견하면 AuthenticationException을, 인가 문제를 발견하면 AccessDeniedException을 throw
  • ExceptionTranslationFilter
    • FilterSecurityInterceptor에 의해 호출됨
    • FilterSecurityInterceptor에서 발생한 예외 처리
      • AuthenticationException
      • AccessDeniedException

 

 

 

 

인증 예외 처리 (AuthenticationException)

인증 예외를 처리하는 방법에는 두가지 방법이 존재한다.

 

  • AuthenticationEntryPoint 호출 : 로그인 페이지로 이동, 401 오류 코드 전달 등 예외 처리
    • 인증 예외 발생 전의 요청 정보를 저장
      • RequestCache : 사용자의 이전 요청 정보를 세션에 저장하여 사용할 수 있는 캐시 메커니즘 제공
      • SavedRequest : 사용자가 요청했던 request의 파라미터, 헤더값 저장
  • SpringContext의 authentication에 사용자의 요청 정보를 저장
    • 인증 예외는 사용자 인증(authentication객체)이 존재하지 않아 발생
    • Filter를 통해서 SecurityContext에 authentication 객체를 저장하면 계속 인증을 유지 할 수 있음

 

 

 

 

 

인가 예외 처리 (AccessDeniedException)

 

인가 예외처리에는 AccessDeniedHandler를 사용할 수 있다.

  • AccessDeniedHandler 호출
    • AccessDecisionManager
      • 인증,요청,권한 정보를 이용해 사용자의 자원접근을 허용/거부 여부를 최종 결정하는 주체
      • 여러 Voter를 가질 수 있고 Voter의 리턴 값을 이용해 판단
    • AccessDecisionVoter
      • 접근 허가 여부를 판단하고 AccessDecisionManager에게 반환

 

 

 

 

 

문제가 해결된 이유

이전 게시글에 작성되었던 Filter를 다시보자

class AuthenticationFilter(
// ... 생략 
) : OncePerRequestFilter() {

    override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, filterChain: FilterChain) {
        val token = resolveToken(request)
        checkIsValidToken(accessToken)
        val authentication = //... 생략 
        SecurityContextHolder.getContext().authentication = authentication
        filterChain.doFilter(request, response)
    }

    private fun resolveToken(request: HttpServletRequest): String? {
        val bearerToken = request.getHeader("Authorization")
        if (bearerToken != null && bearerToken.startsWith("Bearer ")) {
            return bearerToken.substring(7)
        }
        return null
    }

    private fun checkIsValidToken(token: String?) {
        if (!isValidAccessToken(accessToken)) {
            throw InvalidTokenException("유효하지 않은 사용자입니다. token : $token")
        }
    }
}

 

 

 

여기서 Filter에서 발생한 예외를 따로 처리해주는 Filter를 만들어주지 않았는데 어떻게 예외 처리가 될 수 있었던 걸까? 🤔

 

 

@Component
class AuthenticationEntryPoint(
    private val objectMapper: ObjectMapper,
) : AuthenticationEntryPoint {
    override fun commence(
        request: HttpServletRequest,
        response: HttpServletResponse,
        exception: AuthenticationException,
    ) {
        val errorResponse = ErrorResponse.of(exception)
        //... 생략 Object Mapper를 이용해서 Json타입의 ErrorResponse로 반환하도록 수정
    }
}

바로 AuthenticationEntryPoint 때문이다...!

 

 

AuthenticationFilter에서 SpringContext에 authentication 정보를 넣어주기 전에 에외가 발생하여 인증이 이루어지지 않았고, 사용자 인증이 되지 않아 AuthenticationException이 발생했는데 이를 AuthenticationEntryPoint에서 처리해주었기 때문에 원하는 대로 예외 처리가 적용되었다.

 

즉, AuthenticationEntryPoint가 Filter에서 발생한 custom예외가 아닌 인증이 되지 않아 발생된 AuthenticationException를 처리해주었기 때문에 예상한 대로 동작한 것이다.

 

 

 

 

 

 

이렇게 Filter와 Interceptor, Spring Security 인증 / 인가 예외와 처리 방법에 대해서 공부하고 나서야 코드가 어떻게 동작하게 된 것인지 제대로 파악하게 되었다.

 

 

 

 

왜 취준때보다 지식이 사라졌니,,, ✨

원래 팀에 합류했을때 같은 내용으로 리더님이 강의를 해주신 적이 있는데, 주먹 구구 식으로 구현하다보니 금세 잊고 구현하고 있던 나,,,

반성하면서 다시 한번 정리해본다,,, ✨

 

 

+

( 지금은 리더님이 알려주신 내용으로 얕게 공부해놓았기 때문에

스프링 시큐리티는 강의도 듣고 책도 보면서 내용을 정리할 예정이다! 💪🏼 )

 

 

 

끝 ✨

 

 

 

 

 

(참고한 사이트)

https://velog.io/@dailylifecoding/spring-security-exception-handling-and-request-caching

 

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

인증, 인가 예외를 처리하는 방식과 그 과정에서 사용되는 요청 캐싱을 알아보자.

velog.io

https://anjoliena.tistory.com/108

 

SpringSecurity(AccessDenied) 인증거부처리

인증은 성공했으나 서버자원에 접근하려 했을때 사용자의 권한이 서버자원에 접근가능한 권한이랑 일치하지 않을때 인가예외가 발생하게되는데 인가예외는 인증필터가 처리 하는게 아니고 Fil

anjoliena.tistory.com

https://velog.io/@coastby/SpringSecurity-filter-%EB%82%B4%EC%97%90%EC%84%9C-%EB%B0%9C%EC%83%9D%ED%95%9C-%EC%98%88%EC%99%B8-%EC%B2%98%EB%A6%AC%ED%95%98%EA%B8%B0

 

[SpringSecurity] filter 내에서 발생한 예외 처리하기

REST 예외를 처리하기 위해 일반적으로 Spring MVC에서 @ControllerAdvice 및 @ExceptionHandler를 사용하지만 이러한 핸들러는 요청이 DispatcherServlet에 의해 처리되는 경우 작동한다. 그러나 보안 관련 예외는

velog.io

https://velog.io/@seongwon97/Spring-Security-%EC%9D%B8%EC%A6%9D%EC%9D%B8%EA%B0%80%EC%9D%98-Exception

 

[Spring Security] 인증/인가의 Exception

Spring Security에서 인증/인가에 대한 예외처리는 FilterSecurityFilter와 ExceptionTranslationFilter가 처리를 하게 됩니다.

velog.io

https://willbfine.tistory.com/553

 

<Spring Security> 3. 인증&인가 처리 과정

출처 : https://inf.run/4Vam 스프링 시큐리티 - Spring Boot 기반으로 개발하는 Spring Security - 인프런 | 강의 초급에서 중.고급에 이르기까지 스프링 시큐리티의 기본 개념부터 API 사용법과 내부 아키텍처

willbfine.tistory.com

https://catsbi.oopy.io/f9b0d83c-4775-47da-9c81-2261851fe0d0

 

스프링 시큐리티 주요 아키텍처 이해

목차

catsbi.oopy.io

https://coder-in-war.tistory.com/entry/Spring-Security-05-%EC%9D%B8%EC%A6%9D%EC%9D%B8%EA%B0%80-API%EC%9D%98-%EC%98%88%EC%99%B8%EC%B2%98%EB%A6%AC

 

[ Spring Security ] 05. 인증/인가 API의 예외처리

인프런에서 진행하는 정수원 강사님의 "스프링 시큐리티 - Spring Boot 기반으로 개발하는 Spring Security" 강의를 보고 학습을 위해 개인적으로 추가/정리한 글임을 알립니다. 인증/인가 API ExceptionTrans

coder-in-war.tistory.com