개발 일기

[Spring Boot] JWT를 활용한 인증(Authentication) 및 인가(Authorization) 처리 과정 본문

Back-End/Spring

[Spring Boot] JWT를 활용한 인증(Authentication) 및 인가(Authorization) 처리 과정

개발 일기장 주인 2024. 10. 20. 22:59

https://github.com/TanJi-LL/Tanji-Backend

해당 블로그는 위 프로젝트에서 내가 직접 구현한 Spring Boot 프로젝트에서 직접 사용한 JWT를 활용한 인가(Authorization)처리 과정을 정리해보고자 한다.

지금부터 설명하고자하는 로직은 회원가입이나 로그인 과정이 아닌, 특정 API 요청을 보낸 사용자가 해당 리소스에 대한 권한이 있는지 확인하는 인가(Authorization) 과정을 처리하기 위한 로직에 대한 설명이다

인가(Authorization) 처리 흐름도 및 설명

우선 처음으로 JwtExceptionFilter로 들어간다.

 

1. JwtExceptionFilter

해당 필터에서는 JWT 처리 중 발생하는 예외를 처리하며, 예외 발생 시 사용자에게 적절한 응답을 반환하는 역할을 한다고 생각하면 된다.

JwtCustomException 발생 시 이를 잡아 HttpResponseUtil를 사용하여 적절한 에러 메시지와 상태 코드를 포함한 응답을 반환한다.

사실 직접적인 인가처리를 하는 필터로 볼 수는 없고 주로 엑세스 토큰 검증 중에 throw 되는 예외를 캐치하고 적절한 응답으로 반환하는 역할을 해준다.

 

2. JwtAuthenticationFilter

유저의 Request에서 JWT 토큰을 파싱해서 이를 검증하고 검증에 성공하면 토큰에서 데이터를 끌어와 인증 객체(Authentication)를 생성하여 Spring Security의 SecurityContext에 설정하여 인증된 사용자 정보를 담는 역할을 한다.

 

3. JwtUtil

이제 JwtAuthenticationFilter는 JwtUtil의 validateToken()을 호출하고 해당 메소드에서 실제로 토큰을 검증하는 역할을 한다.

토큰의 유효성을 검증합니다. 만료된 토큰(ExpiredJwtException), 잘못된 형식의 토큰(MalformedJwtException), 서명 불일치(SignatureException) 등의 경우 예외를 발생시키고, 각 예외에 맞는 JwtCustomException을 던진다.

이때 throw한 예외들을 JwtExceptionFilter에서 캐치하여 Http Response 처리를 하게한다.

 

4. CustomUserDetailsService

해당 클래스는 JwtAuthenticationFilter에서 토큰 검증에 성공한 유저에 대해 인증 객체를 생성할때 JwtUtil의 resolve()메소드를 사용하게 되는데 resolve() 메소드에서 CustomuserDetailsService의 loadUserByUsername()메소드를 실행하게 된다. 이때 인자로 토큰에서 파싱한 Subject로 넣어둔 유저 식별자 member_id를 인자로 넣어주고 

이 클래스에서 멤버를 조회하여 해당 정보 값 들로 인증 객체를 생성한다.

 

위의 과정을 모두 거치게 되면 SecurityContextHolder에 인증객체가 담기게 되는데

 

5. JwtAuthenticationEntryPoint

만약 Spring Security에서 인증되지 않은 사용자 요청을 처리할 때는 JwtAuthenticationEntryPoint가 쓰인다. 사용자가 로그인이 필요한 API에 인증 없이 접근하려고 할 때, 인증 예외(AuthenticationException)가 발생하며, 이 클래스가 해당 예외를 처리한다. 이를 통해 인증되지 않은 사용자의 요청에 대해 적절한 에러 응답을 반환하는 역할을 하게 된다.

 

6. JwtAccessDeniedHandler

그리고 마지막으로 JwtAccessDeniedHandler 클래스는 Spring Security에서 인증된 사용자가 권한이 없는 리소스에 접근할 때 발생하는 예외를 처리하는 역할을 합니다. 사용자가 인증을 완료했지만 특정 리소스에 접근할 권한이 없을 때 발생하는 AccessDeniedException을 잡아 적절한 응답을 반환하는 역할을 한다.

@PreAuthorize, @PostAuthroize, @Secured 등으로 권한 검증을 거치는 중 권한이 없는 경우 해당 핸들러로 처리된다.


전체적인 흐름 요약

먼저, JwtExceptionFilter가 JWT 검증 중 발생하는 예외를 처리하며, 검증 중 발생한 예외에 대해 적절한 에러 응답을 반환한다. JwtAuthenticationFilter는 요청에서 JWT를 추출해 검증한 뒤, 성공 시 인증 객체를 생성해 SecurityContext에 저장한다. 이 과정에서 JwtUtil이 JWT의 유효성을 검사하고, 예외가 발생하면 이를 JwtExceptionFilter에서 처리한다. 이후, CustomUserDetailsService가 검증된 토큰의 사용자 정보를 조회해 인증 객체를 생성한다. 인증되지 않은 사용자가 접근할 경우 JwtAuthenticationEntryPoint가 예외를 처리하여 에러 응답을 반환하며, 인증은 되었지만 권한이 없는 사용자에 대해서는 JwtAccessDeniedHandler가 적절한 응답을 반환한다. 이러한 흐름을 통해 API 요청 시 JWT 검증, 예외 처리, 인증 및 권한 관리를 수행한다.