Spring Security 동작 원리 이해하기

dev-well-being·2023년 9월 10일
2
post-thumbnail
post-custom-banner

Spring Security란?

  • 스프링 시큐리티(Spring Security)는 스프링 기반 어플리케이션의 보안(인증과 권한, 인가)을 담당하는 스프링 하위 프레임워크
  • 보안과 관련해서 체계적으로 많은 옵션들을 제공해주기 때문에 개발자의 입장에서는 하나하나 보안 관련 로직을 작성하지 않아도 된다는 장점이 있다.

Spring Security 용어

  • 인증(Authentication) : 해당 사용자가 본인이 맞는지를 확인하는 절차
  • 인가(Authorization) : 인증된 사용자가 요청한 자원에 접근 가능한지를 결정하는 절차
  • 접근 주체(Principal) : 보호받는 Resource에 접근하는 대상
  • 비밀번호(Credential) : Resource에 접근하는 대상의 비밀번호
  • 권한 : 인증된 주체가 어플리케이션의 동작을 수행할 수 있도록 허락되어 있는 지를 결정
    • 인증 과정을 통해 주체가 증명된 이후 권한을 부여할 수 있다.
    • 권한 부여에도 두 가지 영역이 존재하는데 웹 요청 권한과 메서드 호출 및 도메인 인스턴스에 대한 접근 권한 부여

인증(Authentication) -> 인증 성공 후 -> 인가(Authorization)

  • Spring Security는 기본적으로 인증 절차를 거친 후에 인가 절차를 진행하게 되며, 인가 과정에서 해당 리소스에 대한 접근 권한이 있는지를 확인하게 된다.
  • 이러한 인증과 인가를 위해 Principal을 아이디로, Credential을 비밀번호로 사용하는 인증 방식을 사용한다.
  • 기본적으로 인증 정보는 인메모리 세션 저장소인 SecurityContextHolder에 세션 - 쿠키 방식으로 저장

Spring Security 동작 과정

HTTP 요청 수신

  • 클라이언트(브라우저)로 부터 요청(Request)이 오면 인증 및 권한 부여 목적으로 일련의 필터를 거친다.
  • 일반적으로 ID, PASSWORD 기반의 인증이라고 할 경우 가장 먼저 Application Filters라는 필터 뭉치에 도달한다.
  • 다음으로 username, password를 사용하는 form 기반 인증을 처리하는 필터인 UsernamePasswordAuthenticationFilter에 도착하게 된다.
  • id, password가 아닌 OAuth2.0 인증이나 JWT를 이용한 인증을 하려고 할 때는 해당 필터가 아닌 다른 필터를 거치게 된다.(ex:OAuth2ClientAuthenticationProcessingFilter)

  • UsernamePasswordAuthenticationFilter에 요청이 도착하면 해당 클래스의 attempAtuhentication(request, response) 메서드가 동작.
  • 이 메서드는 request로부터 username, password를 가지고 와서 사용자 자격 증명을 기반으로 한 UsernamePasswordAuthenticationToken(Authentication)을 생성한다.
  • UsernamePasswordAuthenticationToken(Authentication)을 가지고 AuthenticationManager(실질적으로 구현체인 ProviderManager)에게 인증을 진행하도록 위임.
  • UsernamePasswordAuthenticationToken은 Authentication 인터페이스의 구현체이다. 객체 간의 구조를 뜯어보면 UsernamePasswordAuthenticationToken이 AbstractAuthenticationToken을 extends, AbstractAuthenticationToken은 Authentication을 implements하는 구조로 설계되어 있음
  • 모든 접근 주체는 Authentication을 생성. 이것은 최종적으로 SecurityContext에 보관되고 사용

AuthencationManager(Interface)

  • Authentication 객체를 받아 인증하고, 인증되었다면 인증된 Authentication 객체를 돌려주는 authenticate()메서드를 구현하도록 하는 인터페이스
  • 이 메서드를 통해 인증이 되면 isAuthenticated(boolean) 값을 true로 바꿔준다.

ProviderManager(Class)

  • AuthenticationManager의 구현체로 스프링에서 인증을 담당하는 클래스
  • 스프링 시큐리티가 생성, 등록하고 관리하는 스프링 빈이기 때문에 직접 구현할 필요는 없음.
  • ProviderManager 클래스는 인증을 담당하고 있지만 실제로 인증 과정을 진행하는게 아니라 멤버 변수로 가지고 있는 AuthenticationProvider에게 인증을 위임하고 그 중에서 인증 처리가 가능한 AuthenticationProvider 객체가 인증 과정을 거쳐서 인증에 성공하면 요청에 대해 ProviderManager가 인증이 되었다고 알려주는 방식
  • 인증이 되었다고 알려주는 건 AuthenticationManager 인터페이스의 authenticate() 메서드의 리턴 값인 Authentication 객체 안에 인증 값을 넣어주는 것으로 처리

AuthenticationProvider (Interface)

  • AuthenticationManager와 같은 authenticate() 메서드를 통해 인증 과정이 진행

  • supports(Class<?>) 메서드는 앞에서 필터를 통해 보내준 Authentication 객체를 이 AuthenticationProvider가 인증 처리가 가능한 클래스인지를 확인하는 메서드

  • AuthenticationProvider가 인터페이스이기 때문에 해당 인터페이스를 구현하는 클래스를 만들어 인증처리를 하는 로직을 구현하면 된다.(UserDetailService, UserDetail 등등)

  • 이렇게 구현된 인증 절차를 통해 인증이 완료되면 Authentication을 SecurityContextHolder 객체 안의 SecurityContext에 저장

SecurityContextHolder

  • SecurityContext 객체를 저장하고 감싸고 있는 wrapper 클래스로 SecurityCotextHolder는 보안 주체의 세부 정보를 포함하여 응용 프로그램의 현재 보안 콘텍스트에 대한 세부 정보가 저장되어 있음

SecurityContext

  • Authentication을 보관하는 역할을 하며, SecurityContext를 통해 Authentication 객체를 꺼내올 수 있다.
  • ThreadLocal에 저장되어 아무 곳에서나 참조가 가능하도록 설계

DelegatingFilterProxy

  • Spring security를 설정하게 된다면 DispatcherServlet에 도달하기 전에 서블릿 Filter 구현체에게 걸린다.
  • FilterChain들을 Servelt Container 기반의 필터 위에서 동작하기 위해 중간 연결을 위한 DelegatingFilterProxy를 사용
  • DelegatingFilterProxy는 IOC 컨테이너에서 관리하는 빈이 아닌 표준 서블릿 필터를 구현하고 있으며 내부적으로 요청을 위임할 (FilterChainProxy)을 가지고 있다.
  • DelegatingFilterProxy은 Servlet Container 기반의 필터 위에서 동작하기 위해서 중간 역할만 하고 FilterChainProxy에게 요청 처리를 위임

참고자료

https://wildeveloperetrain.tistory.com/50
https://k3068.tistory.com/88

profile
안녕하세요!! 좋은 개발 문화를 위해 노력하는 dev-well-being 입니다.
post-custom-banner

0개의 댓글