스프링 시큐리티 - 주요 아키텍쳐 이해

Seung jun Cha·2022년 8월 6일
0

1. DelegatingProxyChain, FilterChainProxy

  • 스프링 빈은 스프링 컨테이너(예: ApplicationContext)에서 관리되는 객체로 스프링 빈은 스프링 컨테이너가 생성하고 관리하므로 서블릿 필터가 직접 빈에 접근하거나 주입받는 것이 불가능.

  • 스프링 시큐리티는 서블릿 필터를 사용하여 웹 요청을 보호합니다. DelegatingFilterProxy는 이러한 스프링 시큐리티 필터를 서블릿 필터와 통합하는 역할을 합니다.

  • 서블릿 필터는 스프링 빈에 직접 접근하지 않지만, DelegatingFilterProxy를 통해 스프링 컨테이너에서 관리되는 빈을 사용할 수 있습니다.

  • 그래서 서블릿 필터가 관리하는 DelegatingFilterProxySpringSecurityFilterChain(=FilterChainProxy) 이름으로 생성된 빈에 요청을 위임 그 후, DelegatingFilterProxy이름으로 필터 등록

  • FilterChainProxy : SpringSecurityFilterChain 의 이름으로 생성된 빈으로 DelegatingFilterProxy의 요청을 위임받아 실제 보안처리를 함.
    스프링 시큐리티 초기화 시 생성되는 기본필터들과 사용자가 생성한 필터들을 관리하고 제어

2. Authentication

  • 사용자의 인증 정보를 저장하는 토큰 개념
    인증 시 id 와 password 를 담고 인증 검증을 위해 전달되어 사용된다
    인증 후 user 객체, 권한정보 를 담고 SecurityContext 에 저장되어 전역적으로 참조가 가능하다
Authentication authentication = SecurityContexHolder
.getContext()
.getAuthentication()

2-1 구조

  1. principal : 사용자 아이디 혹은 User 객체를 저장
  2. credentials : 사용자 비밀번호
  3. authorities : 인증된 사용자의 권한 목록
  4. details : 인증 부가 정보
  5. Authenticated : 인증 여부


1. UsernamePasswordAuth필터가 입력받은 아이디와 비밀번호를 추출해서 Authentication 객체를 만들고 AuthenticationManager에 전달
2. AuthenticationManager에서 인증처리를 하고 성공하면 Authentication 객체를 만들어서 SecurityContextHolder에 전달

3 SecurityContextHolder, SecurityContext

3-1 SecurityContext

1. Authentication 객체가 저장되는 보관소로 필요 시 언제든지 Authentication 객체를 꺼내어 쓸 수 있도록 제공되는 클래스
2. ThreadLocal 에 저장되어 아무 곳에서나 참조가 가능하도록 설계함
3. 인증이 완료되면 HttpSession에 저장되어 어플리케이션 전반에 걸쳐 전역적인 참조가 가능하다

3-2 SecurityContextHolder

  • SecurityContext 객체 저장 방식

    • MODE_THREADLOCAL : 스레드당 SecurityContext 객체를 할당, 기본값
    • MODE_INHERITABLETHREADLOCAL : 메인 스레드와 자식 스레드에 관하여 동일한 SecurityContext 를 유지
    • MODE_GLOBAL : 응용 프로그램에서 단 하나의 SecurityContext를 저장한다
  • SecurityContextHolder.clearContext() : SecurityContext 기존 정보 초기화

  • 로그인을 하면 사용자의 요청을 받은 쓰레드와 쓰레드 전역 저장소가 생성됨

4. SecurityContextPersistenceFilter

  • 사용자 요청을 받을 때마다 SecurityContext 객체의 생성, 저장, 조회

  • 익명 사용자
    새로운 SecurityContext 객체를 생성하여 SecurityContextHolder 에 저장
    AnonymousAuthenticationFilter 에서 AnonymousAuthenticationToken 객체를 SecurityContext 에 저장

  • 아이디와 비밀번호로 인증 시
    새로운 SecurityContext 객체를 생성하여 SecurityContextHolder 에 저장
    UsernamePasswordAuthenticationFilter 에서 인증 성공 후 SecurityContext 에 UsernamePasswordAuthentication token객체를 SecurityContext 에 저장
    인증이 최종 완료되면 Session 에 SecurityContext 를 저장

  • 인증 후
    Session 에서 SecurityContext 꺼내어 SecurityContextHolder 에서 저장
    SecurityContext 안에 Authentication 객체가 존재하면 계속 인증을 유지한다

  • 최종 응답 시 공통 : 요청에 응답 시 Holder에서 Context를 제거하고 response
    SecurityContextHolder.clearContext()

5. 전체 인증 흐름의 이해

  • 여기에 표시는 안되어 있지만 사용자가 사이트에 접속한다면 최초에는 무조건 익명사용자이다.
    익명사용자가 사이트에서 인증을 시도할 수도 있고 하지 않을 수도 있고,
    인증 이후 로그아웃 한다면 다시 익명사용자가 된다.
    그래서 무조건 익명사용자용 AnonymousAuthenticationProvider 는 필요한 것이라 보시면 됩니다.
    스프링 시큐리티는 로그인하지 않은 사용자 즉 익명사용자를 구분하기 위한 별도의 프로세스를 관리하고 있다고 보시면 됩니다.

6. AuthenticationManager, Provider(UserDetailService)

  • 스프링 시큐리티에서 인증은 AuthenticationManager를 통해 이루어지며, AuthenticationManagerBuilder가 AuthenticationManager를 생성한다. 전체적인 설정은 AuthenticationManager에 하고 실제 인증처리는 AuthenticationProvider에서 진행한다.
 @Bean
    protected void AuthenticationManager(AuthenticationManagerBuilder auth)
    {
        auth.userDetailsService(memberService)  
        // userDetailsService 를 구현하고 있는 객체를 지정
                .passwordEncoder(passwordEncoder());
    }   ==> 스프링 부트 버전 업데이트 이후 없어도 되는 코드
  • AuthenticationProvider 목록 중에서 인증 처리 요건에 맞는 AuthenticationProvider 를 찾아 인증처리를 위임한다
    부모 ProviderManager 를 설정하여 AuthenticationProvider 를 계속 탐색 할 수 있다
  • UserDetailService 인터페이스는 DB에서 회원정보를 가져오는 역할을 한다. 인터페이스를 구현하여 그 안에 loadUserByUsername() 메서드로 회원정보를 조회하고, UserDetailService가 repository에서 찾아온 유저의 정보는 User 객체로 만들어져 반환된다. 그리고 입력받은 아이디와 비밀번호가 담긴 Authetication와 실제 아이디, 비밀번호를 비교해서 검증한다.

7. Authorization

  • 인증 받은 사용자에게 무엇이 허가 되었는지 증명하는 것

  • FilterSecurityInterceptor

  1. 마지막에 위치한 필터로써 인증된 사용자에 대하여 특정 요청의 승인/거부 여부를 최종적으로 결정
  2. 권한 제어 방식 중 HTTP 자원의 보안을 처리하는 필터
  3. 권한 처리를 AccessDecisionManager에게 맡김

7-1 AccessDecisionManager

  • 인증 정보, 요청정보, 권한정보를 이용해서 사용자의 자원접근을 허용할 것인지 거부할 것인지를 최종 결정하는 주체
    여러 개의 Voter 들을 가질 수있으며 Voter 들로부터 접근허용, 거부, 보류에 해당하는 각각의 값을 리턴받고 판단 및 결정
    최종 접근 거부 시 예외 발생
  1. AffirmativeBased : 기본값으로 여러개의 Voter 클래스 중 하나라도 접근 허가로 결론을 내면 접근 허가로 판단한다.

  2. ConsensusBase : 다수표(승인 및 거부)에 의해 최종 결정을 판단한다
    동수일경우 기본은 접근허가이나 allowIfEqualGrantedDeniedDecisions 을 false 로 설정할 경우 접근거부로 결정된다

  3. UnanimousBased : 모든 보터가 만장일치로 접근을 승인해야 하며 그렇지 않은 경우 접근을 거부한다

7-2 AccessDecisionVoter

  • Voter 가 권한 부여 과정에서 판단하는 자료
    • Authentication - 인증 정보(user)
    • FilterInvocation – 요청 정보 (antMatcher("/user"))
    • ConfigAttributes - 권한 정보 (hasRole("USER"))
  • 결정 방식
    • ACCESS_GRANTED : 접근허용(1)
    • ACCESS_DENIED : 접근 거부(-1)
    • ACCESS_ABSTAIN : 접근 보류(0)
      Voter 가 해당 타입의 요청에 대해 결정을 내릴 수 없는 경우

8. 전체 과정

0개의 댓글