2학년 2학기 코부엉이라는 코딩동아리에 들어가서 처음으로 프로젝트에 참여하게 되었다. 50명이 넘는 인원이 프로젝트에 참여중이고 나는 백엔드 부분에서 Login 기능을 구현하는 담당을 맡았다. 프로젝트에 들어가니 나는 아무것도 할 줄 아는게 없었고 부회장님이 말한 가장 어려운 부분(Spring Security, JWT)을 맡았다. 내가 왜 부분을 맡을려 했는지... 패기만 있었다ㅋㅋㅋ....
결국 친구 한명과 구글링을 엄청하면서 괜찮은 예제를 찾고 복붙을 해버렸다ㅋㅋㅋ. 부회장님도 우리가 새싹이라는 것을 알고 복붙을 이해해주셨고 그래도 우리가 맡은 부분에 대해 어느 정도는 알고 있어야 하지 않겠냐는 말에 복붙한 코드를 분석하고 구글링한것을 정리하려한다.
: 스프링 기반 어플리케이션의 보안(인증과 권한, 인가)를 담당하는 스프링 하위 프레임워크이다.
Spring Security 기본 용어 및 이론
인증(Authentication) -> 인증 성공 후 -> 인가(Authorization)
Spring Security는 기본적으로 인증 절차를 거친 후에 인가 절차를 진행하게 되며, 인가 과정에서 해당 리소스에 대한 접근 권한이 있는지를 확인하게 됩니다. 이러한 인증과 인가를 위해 Principal을 아이디로, Credential을 비밀번호로 사용하는 인증 방식을 사용합니다.
스프링 시큐리티 전체적인 동작 과정
처음부터 자세히 들어가보자!!

Security에는 일련의 필터 체인이 있습니다. 그래서 클라이언트(브라우저)로 부터 요청(Request)이 오면 인증 및 권한 부여 목적으로 일련의 필터를 거치게 됩니다.
일반적으로 ID, PASSWORD 기반의 인증이라고 할 경우 가장 먼저 Application Filters라는 필터 뭉치에 도달합니다. 그리고 그 필터들 중 Authentication Filters라는 필터 뭉치에 다시 도달합니다. 다음으로 username, password를 사용하는 form 기반 인증을 처리하는 필터인 UsernamePasswordAuthenticationFilter에 도착하게 됩니다.

UsernamePasswoardAuthenticationFilter에 요청이 도착하면 해당 클래스의 attempAuthentication(request, response) 메서드가 동작합니다. 이 메서드는 request로부터 username, password를 가지고 와서 사용자 자격 증명을 기반으로 한 UsernamePasswordAuthenticationToken(Authentication)을 생성합니다.
이어서 생성된 UsernamePasswordAuthenticationToken(Authentication)을 가지고 AuthenticationManager (실질적으로는 구현체인 ProviderManager)에게 인증을 진행하도록 위임합니다.

AuthenticationManager(Interface)
Authentication 객체를 받아 인증하고, 인증되었다면 인증된 Authentication 객체를 돌려주는 authenticate() 메서드를 구현하도록 하는 인터페이스입니다. 이 메서드를 통해 인증이 되면 isAuthenticated(boolean) 값을 true로 바꿔줍니다.
ProviderManager(Class)
AuthenticationManager의 구현체로 스프링에서 인증을 담당하는 클래스로 볼 수 있습니다. 스프링 시큐리티가 생성, 등록하고 관리하는 스프링 빈이기 때문에 직접 구현할 필요는 없습니다.
ProviderManager 클래스는 인증을 담당하고 있지만 실제로 직접 인증 과정을 진행하는 게 아니라 멤버 변수로 가지고 있는 AuthenticationProvider(s)에게 인증을 위임하고 그중에서 인증 처리가 가능한 AuthenticationProvider 객체가 인증 과정을 거쳐서 인증에 성공하면 요청에 대해 ProviderManager가 인증이 되었다고 알려주는 방식입니다.
인증이 되었다고 알려주는 건 AuthenticationManager 인터페이스의 authenticate() 메서드의 리턴 값인 Authentication 객체 안에 인증 값을 넣어주는 것으로 처리합니다.
AuthenticationProvider(Inteface)
AUthenticationManager와 같은 authenticate() 메서드를 통해 인증 과정이 진행됩니다.
boolean supports(Class<?>) 메서드는 앞에서 필터를 통해 보내준 Authentication 객체를 이 AuthenticationProvider가 인증 처리가 가능한 클래스인지를 확인하는 메서드입니다.
실질적인 인증 로직을 위해 AuthenticationProvider interface를 구현한 클래스가 필요한데요. AuthenticationProvider를 implements 하게 되면 authenticate(), supports() 메서드를 구현하게 됩니다.

인증 절차를 통해 인증이 완료되면 Authentication을 SecurityContextHolder 객체 안의 SecurityContext에 저장한다.
Authentication authentication = SecutiryContextHolder.getContext().getAuthentication();
SecutiryContextHolder
SecurityContext 객체를 저장하고 감싸고 있는 wrapper 클래스로 SecurityContextHolder는 보안 주체의 세부 정보를 포함하여 응용프로그램의 현재 보안 콘텍스트에 대한 세부 정보가 저장됩니다.
(MODE_THREADLOCAL, MODE_INHERITABLETHREADLOCAL, MODE_GLOBAL 세 가지 저장 방식이 있습니다.)
SecutiryContext
Authentication을 보관하는 역할을 하며, SecurityContext를 통해 Authentication 객체를 꺼내올 수 있습니다. ThreadLocal에 저장되어 아무 곳에서나 참조가 가능하도록 설계되어 있습니다.
참고 : 스프링 시큐리티 동작방식