들어가기 앞서 . . .
Spring Security는 인증, 검증, 권한 부여를 지원하는 Spring Framework 라이브러리입니다.
많은 개발자들이 편리하게 활용하고 있으며, 저도 몇 번의 프로젝트에서 Spring Security를 적용해 본 경험이 있답니다!
덕분에 인터넷에 자료도 많고, 코드도 넘쳐나니까 복사해서 붙여넣기만 하면 끝! 이렇게 쉽게 적용할 수 있죠.
하지만 스프링과 Security는 계속해서 업데이트가 진행되면서, 버전마다 메소드나 기능이 조금씩 다르기도 해요.
그런 상태에서 이론 없이 다른 사람 코드 가져다가 수정하다 보면, 에러가 나오고 시간이 쏙쏙 빠져나가죠..
그래서 이번에는 직접 공식 문서를 읽고,
Security에 대한 배경 지식도 쌓고, 기억에 남게 정리하고자 이렇게 글을 작성하게 되었습니다.😃
Spring Security
Spring Security는 두 가지에 대한 처리를 위임하는 별도의 프레임 워크입니다.
- 인증(Authentication)
- 인가(Authorization)
Spring Securiy의 인증 인가는 대부분 Filter의 흐름에 따라 처리되는데요! Spring Security는 Servlet Container 내부에 존재하는 Filter에서부터 시작됩니다. Filter는 Dispatcher Servlet 이전에 적용 되므로, 가장 먼저 Url 요청을 받게됩니다.
Spring Security
Spring Security framework가 인증, 인가를 어떻게 처리할까요? 우선 SpringMVC구조부터 천천히 살펴봅시다!

아래 접은 글을 펼치면 Spring MVC구조와 동작 과정을 더 자세하게 볼 수 있습니다!
1️⃣ 클라이언트가 HTTP 요청을 보냄
• 사용자가 브라우저에서 특정 URL을 요청합니다. (/login, /home 등)
2️⃣ DispatcherServlet이 요청을 가로챔
• DispatcherServlet은 모든 요청의 진입점(Front Controller) 역할을 합니다.
• 어떤 컨트롤러(핸들러)가 요청을 처리할지 조회합니다.
3️⃣ HandlerMapping을 통해 컨트롤러 찾기
• 요청에 매핑된 핸들러(Controller) 를 찾습니다.
4️⃣ HandlerAdapter가 컨트롤러 실행
• 컨트롤러를 실행할 수 있도록 적절한 HandlerAdapter를 찾아 실행합니다.
5️⃣ 컨트롤러에서 ModelAndView 반환
• 컨트롤러는 클라이언트에게 응답할 데이터(Model)와 View 정보를 반환합니다.
6️⃣ ViewResolver를 통해 적절한 View 찾기
• 반환된 View 이름을 기반으로 실제 View 파일을 찾습니다.
7️⃣ View를 반환하고 응답을 클라이언트에게 전달
• 최종적으로 렌더링된 HTML을 클라이언트(브라우저)에게 응답합니다.
Spring MVC는 위와 같은 구조로 동작합니다. 이 과정에서 클라이언트가 특정 요청(예: 로그인, 회원 정보 조회 등)을 보낼 경우,
DispatcherServlet에 도달하기 전에 Spring Security의 Filter가 요청을 가로채어 인증(Authentication)과 인가(Authorization) 처리를 먼저 수행하게 됩니다!
그러면 여기서 Spring Security의 Filter가 어떠한 동작을 하는 지 알아볼까요?
Spring Security
Security의 동작 과정은 아래와 같습니다.

너무 낯선 용어와 영어들이 많이 나와 당황하셨죠?
본격적인 동작 원리를 살펴보기 전에, 먼저 각 요소들이 어떤 역할을 하는지 간단히 알아볼게요!
🚀 Spring Security 주요 개념 설명 (쉽게 이해하기)
1. AuthenticationFilter (인증필터)
요청을 처음 가로채는 곳!
사용자가 로그인 요청을 보내면, 제일 먼저 실행되는 필터입니다.
이 필터는 로그인 정보(ID, Password)를 검사하고, UsernamePasswordAuthenticationToken을 생성해, 인증을 처리할 AuthenticationManager로 넘깁니다.
2. UsernamePasswordAuthenticationToken (사용자 인증 정보)
사용자의 로그인 정보(ID, Password)가 담긴 객체입니다.
이 객체에는 사용자가 입력한 ID와 비밀번호가 들어 있으며,이 정보를 바탕으로 사용자의 신원을 확인합니다.
UsernamePasswordAuthenticationToken은 Authentication을 상속받기 때문에 Authentication 객체로 사용됩니다.
3. AuthenticationManager (인증 관리자)
실제 인증을 진행하는 핵심 인터페이스!
AuthenticationManager는 다양한 방식으로 인증을 수행할 수 있으며, 실제 인증은 AuthenticationProvider에게 위임합니다.
🚀 왜 AuthenticationManager가 필요할까? (AuthenticationProvider만으로 충분하지 않은 이유)
"그럼 그냥 AuthenticationProvider만 있으면 되지 않나?”라는 의문이 들어서 찾아봤습니다.
AuthenticationManager: 인증을 총괄하는 관리자 역할
AuthenticationProvider: 실제 인증을 수행하는 실행자 역할
👉 비유하자면? AuthenticationManager는 면접관 같은 존재이고,AuthenticationProvider는 각 분야별 전문 면접관
AuthenticationManager는 여러 개의 AuthenticationProvider를 관리하고, 각 인증 요청을 적절한 AuthenticationProvider에게 위임하는 역할을 합니다.
Spring Security는 여러 개의 인증 방식을 조합할 수 있도록 설계되어 있습니다.
ex) 기본 로그인 (ID/PW) → `DaoAuthenticationProvider`
소셜 로그인 (OAuth2) → `OAuth2AuthenticationProvider`
API 키 인증 → `ApiKeyAuthenticationProvider`
이 경우, 각 인증 방식에 맞는 AuthenticationProvider를 만들어야 하고, AuthenticationManager가 요청을 적절한 AuthenticationProvider에 위임해야 합니다!
즉, AuthenticationManager가 없으면 여러 개의 AuthenticationProvider를 효과적으로 관리할 수 없기떄문에 꼭 AuthenticationManager를 통해 인증 요청을 Provider에게 위임해주어야 합니다.
4. AuthenticationProvider (인증 제공자)
: 실제 로그인 검증을 담당하는 객체!
여러 개의 AuthenticationProvider를 등록할 수 있으며,
각각의 AuthenticationProvider는 특정 인증 방식 (예: ID/PW, JWT, OAuth)을 처리할 수 있습니다.
👉 여기서 중요한 포인트!
AuthenticationProvider는 UserDetailsService를 이용해 사용자 정보를 조회하고 비밀번호를 검증합니다.
5. UserDetailsService (사용자 정보 조회)
: DB에서 사용자의 정보를 가져오는 서비스
사용자의 아이디(ID)를 기반으로 User 정보를 조회하는 역할을 합니다.
주로 Custom 구현체를 만들어 DB와 연결된 UserDetails 객체를 반환하게 됩니다.
6. UserDetails (사용자 정보 객체)
: Spring Security에서 사용하는 사용자 정보 인터페이스
DB에서 조회된 사용자의 정보(ID, 비밀번호, 권한)를 담고 있는 객체입니다. 이 객체는 UserDetailsService를 통해 생성됩니다.
7. SecurityContextHolder (인증 정보 저장소)
: 인증된 사용자의 정보를 저장하는 곳!
로그인이 완료되면, 인증된 Authentication 객체가 SecurityContext에 저장됩니다.
이후 애플리케이션의 모든 요청에서 사용자 정보에 접근할 때 사용됩니다.
8. SecurityContext
: Authentication을 보관하는 역할
SecurityContext를 통해 Authentication 객체를 꺼내올 수 있습니다. ThreadLocal에 저장되어 아무 곳에서나 참조가 가능합니다.
Spring Security 동작 과정
간단하게 용어와 흐름을 파악했으면 Spring Security 인증 과정을 살펴볼까요?
Request 요청을 받게되면 AuthenticationFilter가 요청을 가로챈다고 했는데, Filter는 어떤식으로 작동할까요?

1️⃣ 사용자가 로그인 요청하면(ID/PW 입력) AuthenticationFilter가 요청을 가로채
UsernamePasswordAuthenticationToken 생성
Security에는 일련의 필터 체인이 존재합니다.
클라이언트로부터 요청(Request)이 오면, 인증 및 권한 부여 목적으로 필터를 거치게 됩니다.
일반적으로 ID,PASSWORD 기반의 인증이라고 할 경우, 가장 먼저 Application Filters라는 필터 뭉치에 도달하게 됩니다.
그리고 그 필터 중 Authentication Filters라는 필터 뭉치에 다시 도달하고, username과 password를 사용하는 form 기반 인증 처리 필터인 UsernamePasswordAuthenticationFilter에 도달하게 됩니다
*id, password가 아닌 OAuth2.0 인증이나 JWT를 이용한 인증을 할 때는 해당 필터가 아닌 다른 필터를 거치게 됩니다.
(ID/PASSWORD 기반 인증 - UsernamePasswordAuthenticationFilter)
(OAuth2.0 - OAuth2ClientAuthenticationProcessingFilter)
(JWT -OncePerRequestFilter)

Http Request의 요청을 받게되면 위에 말한 AuthenticationFilter에서 요청을 낚아채고, (ID/PASSWORD기반 로그인일 경우) UsernamePasswordAutehnticationFilter에 요청이 도착하면 해당 클래스의 attempAuthentication(request, response) 메서드가 동작하게 됩니다.
attempAuthentication(): request로부터 username, password를 가지고 와서 사용자 자격 증명을 기반으로 한
UsernamePasswordAuthenticationToken(Authentication)을 생성합니다.
이어서 생성된 UsernamePasswordAuthenticationToken(Authentication)을 가지고 AuthenticationManager에게 인증을 진행하도록 위임합니다!
*UsernamePasswordAuthenticationToken은 Authentication 인터페이스의 구현체 입니다.
객체 간의 구조를 뜯어보면 UsernamePasswordAuthenticationToken이 AbstractAuthenticationToken을 상속받고,
AbstractAuthnticationToken은 Authentication을 구현하는 구조로 설계되어있습니다.
(너무 복잡하고 이해가 안간다고 생각된다면 UsernamePasswordAuthenticationTokend은 Authentication객체구나~정도로 이해해주시면 됩니다.)
2️⃣ AuthenticationManager가 AuthenticationProvider에게 인증 위임
Authentication 객체를 받아 인증하고, 인증되었다면 인증된 Authentication 객체를 돌려주는 authenticate 메서드를 구현하도록 하는 인터페이스입니다. 이 메서드를 통해 인증이 되면 isAuthenticated(boolean) 값을 true로 바꿔줍니다.
여기서 "ProviderManager"란?
AuthenticationManager의 구현체로, 스프링에서 인증을 담당하는 클래스입니다.
스프링 시큐리티가 생성, 등록하고 관리하는 스프링 빈이기 때문에 직접 구현할 필요는 없습니다.
ProviderManager 클래스는 인증을 담당하고 있지만 실제로 직접 인증 과정을 진행하는 게 아니라 멤버 변수로 가지고 있는 AuthenticationProvider(s)에게 인증을 위임하고 그중에서 인증 처리가 가능한 AuthenticationProvider 객체가 인증 과정을 거쳐서 인증에 성공하면 요청에 대해 ProviderManager가 인증이 되었다고 알려주는 방식입니다.
인증이 되었다고 알려주는 건 AuthenticationManager 인터페이스의 authenticate() 메서드의 리턴 값인 Authentication 객체 안에 인증 값을 넣어주는 것으로 처리합니다.
3️⃣ AuthenticationProvider가 UserDetailsService를 통해 사용자 정보 조회
AuthenticationManager와 같은 authenticate() 메서드를 통해 인증 과정이 진행됩니다.
boolean supports(Class<?>) 메서드는 앞에서 필터를 통해 보내준 Authentication 객체를 이 AuthenticationProvider가 인증 처리가 가능한 클래스인지를 확인하는 메서드입니다.
UserDetailsService의 loadUserByUsername()을 통해 DB에 저장된 이용자 정보를 가져오고, Authentication 객체인 UsernamePasswordAuthenticationToken을 통해 사용자가 입력한 이용자 정보를 가져옵니다.
일치하는 경우 Authentication을 반환하고, 일치하지 않는 경우 Authentication을 반환하지 않기 때문에 이후 반환값이 Authentication이냐에 따라서 인증 성공과 실패를 구분합니다.
4️⃣ DB에서 사용자 정보를 가져와 UserDetails 객체 생성
사용자가 '입력한' 아이디와 비밀번호가 DB에 존재하다면 사용자가 '가입한' 아이디와 비밀번호를 UserDetails에 담아 저장합니다.
5️⃣ AuthenticationManager는 Authentication 객체를 LoginSuccessHandler로 전송한 뒤, SecurityContextHolder에 저장합니다.
성공 시, AuthenticationSucesshandler, 실패 시 AuthenticationFailureHandler가 실행됩니다.
6️⃣ 인증이 완료되면 클라이언트에게 응답 반환
인증이 완료된다면 클라이언트에게 응답을 반환합니다.
아래 접은 글을 열면 간단한 동작 흐름을 보실 수 있습니다!
1️⃣ 사용자가 로그인 요청 (ID/PW 입력)
2️⃣ AuthenticationFilter가 요청을 가로채 UsernamePasswordAuthenticationToken 생성
- 사용자가 '입력한!' 아이디와 비밀번호를 UsernamePasswordAuthenticationToken에 저장하는겁니다!
3️⃣ AuthenticationManager가 AuthenticationProvider에게 인증 위임
4️⃣ AuthenticationProvider가 UserDetailsService를 통해 사용자 정보 조회
1. support(): 메소드가 실행 가능한지 체크 (AuthenticationProvider가 어떤 인증을 지원하는지 지정하는 역할)
2. authentication() : 메소드를 통해 DB에 저장된 이용자 정보와 입력한 로그인 정보
1. DB 이용자 정보: UserDetailService의 loadUserByUsername()을 통해 불러옵니다.
2. 입력 로그인 정보: 3번에서 받았던 Authentication 객체인 UsernameAuthenticationToken을 통해 불러옵니다.
3. 일치하는 경우 Authentication 반환
5️⃣ DB에서 사용자 정보를 가져와 UserDetails 객체 생성
- 사용자가 '입력한!' 아이디와 비밀번호가 DB에 존재하다면 사용자가 '가입한!' 아이디와 비밀번호를 UserDetails에 담아 저장합니다!
6️⃣ AuthenticationManager는 Authentication 객체를 LoginSuccessHandler로 전송한 뒤, SecurityContextHolder에 저장합니다. 성공 시, AuthenticationSucesshandler, 실패 시 AuthenticationFailureHandler가 실행됩니다.
7️⃣ 인증이 완료되면 클라이언트에게 응답 반환
마무리하며
지금까지 Spring Security의 용어와 인증과정에 대해서 알아보았습니다!
이렇게 인증 과정이 어떻게 동작하는지 알았으니, 다음 글에서는 JWT에 대해 다루고, 직접 코드로 구현하는 실습 글로 돌아오겠습니다!
처음 접하면 어렵고 복잡하지만 하나씩 이해하고나니 정말 강력하고 유연한 인증 프레임워크라는 걸 알 수 있었던 기회였던 것 같아요.
이제 직접 코드로 적용해 보면서 Security를 정복해봅시다!
'Spring > Security' 카테고리의 다른 글
| [Spring OAuth] Jwt 적용한 카카오 소셜로그인 Postman으로 테스트하기 (0) | 2025.03.25 |
|---|