Notice
Recent Posts
Recent Comments
Link
«   2025/03   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
Archives
Today
Total
관리 메뉴

개발자

[Spring Security] 스프링 시큐리티 동작 원리 - 1 본문

개발자/workflow 리팩토링 프로젝트(SpringBoot,JPA,MySQL)

[Spring Security] 스프링 시큐리티 동작 원리 - 1

GoGo개발 2023. 7. 1. 00:38

JWT 토큰을 이용해서 로그인을 구현하기 전 스프링 시큐리티를 먼저 적용해려보려고 합니다. 저번 포스팅에서 암호화할때 스프링 시큐리티를 다뤘지만 동작원리는 다른 블로그로 갈음했었는데요. 확실히 동작원리를 알고있지 않으면 원하는대로 필터나 인터셉터등을 커스텀하기가 어렵습니다 . 때문에 이번 포스팅에서 스프링 시큐리티 동작원리를 자세히 살펴도록 합시다

 

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

 

저번 포스팅 에서 썻듯이 시큐리티는 인증과, 인가가 중요한 용어입니다.

 

Authentication(인증)은 말 그대로 사용자가 인증하는 과정을 뜻하며(해당 사용자가 본인이 맞는지를 확인하는 절차)

Authorization(인가)은 서버가 사용자에 대한 권한을 부여하는 것을 말한다.(인증된 사용자가 요청한 자원에 접근 가능한지를 결정하는 절차)

 

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

Spring Security는 기본적으로 인증 절차를 거친 후에 인가 절차를 진행하게 되며, 인가 과정에서 해당 리소스에 대한 접근 권한이 있는지를 확인하게 됩니다. 이러한 인증과 인가를 위해 Principal을 아이디로, Credential을 비밀번호로 사용하는 인증 방식을 사용합니다.

 

  • 접근 주체 Principal : 보호받는 Resource에 접근하는 대상
  • 비밀번호 Credential : Resource에 접근하는 대상의 비밀번호
  • 권한 : 인증된 주체가 어플리케이션의 동작을 수행할 수 있도록 허락되어 있는지를 결정합니다.
              - 인증 과정을 통해 주체가 증명된 이후 권한을 부여할 수 있습니다.
              - 권한 부여에도 두 가지 영역이 존재하는데 웹 요청 권한과 메서드 호출 및 도메인 인스턴스에 대한 접근 권한 부여가 있습니다.

기본적으로 인증 정보는 최종적으로 인메모리 세션 저장소인 SecurityContextHolder에 세션 - 쿠키 방식으로 저장됩니다.

위 그림은 스프링 시큐리티 전체 동작과정인데요 하나씩 살펴보겠습니다.

하지만 살펴보기전 알아야 할 것이 있는데요.

 

스프링 시큐리티의 주요 아키텍처중 하나인 DelegatingFilterProxy 입니다.

 

이전에 포스팅했지만 짧게 필터를 설명하고 넘어가자면 

 

WAS에서 실행된 요청이 오면 이 요청이 서블릿으로 들어오는데, 서블릿에 들어오기 전에 처리를 하는 것이 필터입니다.

 

필터의 흐름

HTTP 요청 -> WAS -> 필터 -> 서블릿 -> 컨트롤러

필터 체인

HTTP 요청 -> WAS -> 필터 1 -> 필터 2 -> 필터 3 -> 서블릿 -> 컨트롤러

 

request가 들어오면 필터 과정을 거친 뒤 스프링 컨텍스트로 넘어오게 됩니다. 스프링 시큐리티는 서블릿 필터기반으로 동작하는데 서블릿과 스프링의 컨텍스트는 다릅니다. 서블릿은 톰캣과 같은 WAS 단에서 동작하며 모든 웹 요청을 먼저 처리합니다. 앞선 필터의 과정을 모두 거치고 난 다음에야 요청은 스프링 컨텍스트로 넘어오게됩니다. 따라서 필터는 Servlet 스펙에 있는 기술이기 때문에 Servlet 컨테이너에서만 생성되고 실행됩니다. Spring의 Ioc 컨테이너와는 컨테이너가 다르기 때문에 Spring Bean으로 Injection하거나 Spring에서 사용되는 기술을 Servlet에서 사용할 수 없습니다. 다시 말하면, 필터에서는 스프링의 기능을 사용할 수 없다는 말입니다. 그렇다면 필터에서도 스프링 기능을 사용하는 방법을 어떻게 만들어냈을까요? 바로 위임(delegation)입니다. 이를 가능하게 해주는 것이 DelegatingFilterProxy 클래스인 것입니다.

 

Servlet Filter는 Selvelt 스펙이기 때문에(위에서 설명한 이유로) 스프링에서 정의된 빈을 주입받아 사용 할 수 없습니다. 하지만 시큐리티를 사용하기 위해서 빈주입이 반드시 필요합니다. 때문에 스프링 시큐리티는 DelegatingFilterProxy를 통해 서블릿 컨테이너에서 요청을 취득하고, 스프링 컨테이너에 존재하는 특정 빈(SpringSecurityFilterChain)을 찾아 요청을 위입합니다. 이 필터는 웹 요청을 받으면 내부에서 스프링 컨테스트의 내의 로직으로 요청을 위임하고, 이필터에서는 내부에 필터를 구현한 빈이 록되어 있고 이빈이 요청을 처리합니다.

 

표준 서블릿 컨테이너와 Spring IOC 컨테이너의 다리 역할을 한다고 생각하시면 됩니다.

 

위의 그림과 같이 위임하는 역할을 하게 되는데 WebSecurityConfigureAdapter는 이제 deprecated되어 이제 사용할 수 없습니다. 

 

그래서 위의 그림과 같이 FilterChain을 사용합니다.위 그림의 FilterChain은 Servlet Container가 관리하는ApplicationFilterChain 입니다. 이러한 설정을 @EnableWebSecurity라는 어노테이션을 등록함으로써 간편하게 사용할 수 있습니다. 이 어노테이션을 적용하면 내부에서 @EnableAuthoConfiguration 어노테이션이 동작하면서

 

1. SecurityFilterAutoConfiguration 클래스에서 DelegatingFilterProxyRegistrationBean를 빈으로 등록한다.

 

2. DelegatingFilterProxyRegistrationBean 클래스 DelegatingFilterProxy 객체를 생성한다. FilterChainProxy를 생성할 때 securityFilterChain을 인수로 받는다.

 

3. this.setTargetBeanName(targetBeanName) DelegatingFilterProxy로 요청이 들어올 때 처리를 위임 할 스프링 빈 이름(springSecurityFilterChain)을 설정한다.(FilterChainProxy 클래스인 springSecurityFilterChain이라는 빈을 등록해줍니다.)

 

 

4.요청이 들어오면 가장 먼저 DelegatingFilterProxy가 필터로 동작하면서 doFilter() 함수가 호출된다. doFilter() 함수는 요청을 위임할 필터(springSecurityFilterChain)를 찾아서 해당 요청을 위임(invokeDelete())한다. springSecurityFilterChain 이름으로 생성된 빈을 AppliatonContext에서 찾아 위임을 요청하는데 이때 실제로 보안처리를 하지는 않는다.

 

 

5.invokeDelete() 함수 호출 시 내부에서 FilterChainProxy의 doFilter() 함수를 호출하고, doFilterInternal() 함수에서는 등록 된 Filter 목록을 가지고 인증/인가 처리를 진행한다.

 

 

이렇게 springSecurityFilterChain이라는 이름으로 빈으로 등록해서 사용하면 됩니다. 저는 Config클래스를 만들어서 PasswordEncoder와  springSecurityFilterChain를 빈으로 등록해주었습니다.

 

@EnableWebSecurity 와 PasswordEncoder에 관한 내용은 아래 포스팅을 참고해주세요

https://gogowlgml.tistory.com/96

 

[SpringSecurity]스프링 시큐리티란?/ PasswordEncoder 스프링 시큐리티를 사용해서 패스워드 암호화 하기

로그인을 구현하기 앞서 패스워드를 먼저 암호화해줄 필요가 있어졌다. 이번 로그인은 spring secutiry를 이용해 구현해줄 것이기 때문에 패스워드도 spring security를 이용해서 해보겠다 Spring Security

gogowlgml.tistory.com

 

스프링 시큐리티는 이렇게 모든 필터를 순회하면서 인증 및 인가 처리를 합니다. 그리고 마지막 필터까지 예외가 발생하지 않으면 나머지 필터를 건너다 결국 스프링의 DispatcherServlet으로 넘어가고 비즈니스 로직을 만나게 되는것입니다.

 

 

출처 - https://soojae.tistory.com/54

FilterChainProxy

  • springSecurityFilterChain의 이름으로 생성되는 필터 빈이다.
  • DelegatingFilterProxy로부터 요청을 위임 받고 실체로 보안을 처리한다.
  • 스프링 시큐리티 초기화 시 생성되는 필터들을 관리하고 제어한다.
    • 스프링 시큐리티가 기본적으로 생성하는 필터
      • WebAsyncManager
      • SecurityContextPersistenceFilter
      • HeaderWriterFilter
      • LogoutFilter
      • AnonymousAuthenticationFilter
      • SessionManagementFilter
    • 설정 클래스에서 API 추가 시 생성되는 필터 
    • 추가되는 필터들 더보기 https://logical-code.tistory.com/194
  • 사용자의 요청을 필터 순서대로 호출하여 전달한다.
  • 사용자 정의 필터를 생성해서 기존의 필터 전후로 추가 가능하다.
  • 마지막 필터까지 인증 및 인가 예외가 발생하지 않으면 보안을 통과한다.

 

 

https://soojae.tistory.com/54

https://somuchthings.tistory.com/195

https://uchupura.tistory.com/24

https://wildeveloperetrain.tistory.com/50

 

https://velog.io/@readnthink/Spring-Security%EC%A0%81%EC%9A%A9%EC%9D%84-%ED%95%98%EB%A0%A4%EB%A9%B4-Security-Filter%EC%9D%98-%EA%B5%AC%EC%A1%B0%EB%A5%BC-%EC%95%8C%EC%95%84%EC%95%BC-%ED%95%9C%EB%8B%A4