[데브코스] Spring Security - 2

Updated: Categories:

W16D1 - ThreadLocal / SecurityContext / 인증과정에 대해 알아보자

Thread

  • Spring에서의 WAS(Tomcat)은 ThreadPool을 생성한다. (기본으로 200개를 생성)
  • 각 스레드는 한 요청을 맡아 작업이 끝날때까지 다른 요청을 받지 않음.
  • 요청이 끝나면 스레드를 반납한다.

image

ThreadLocal

final static ThreadLocal<타입> threadLocalValue = new ThreadLocal<>();
  • 하나의 스레드에서 전역적으로 공유 가능한 변수를 가질 수 있다.
  • 동일 스레드내에서는 어떤 계층에서든지 ThreadLocal 변수에 접근할 수 있다.
  • 하지만 서로 다른 스레드는 서로의 로컬 변수를 참조할 수 없다.
  • 하나의 요청을 맡은 스레드의 작업이 끝날때 반드시 로컬 변수는 clear해야 한다.
    • 다음 요청시 해당 스레드에 변수가 남아있다면 로직 오류가 발생할 수 있기 때문


SecurityContext

image

Authentication

  • 사용자를 표현하는 인증 토큰 인터페이스.
  • 토큰(구현체) 종류는 다음과 같다.
    • AnonymousAuthenticationToken : 익명 사용자를 표현
    • UsernamePasswordAuthenticationToken : 로그인한 사용자를 표현
    • RememberMeAuthenticationToken : remember-me로 로그인된 사용자 표현
  • 내부에는 다음과 같은 정보를 가진다.
    • Principal : 인증여부에 따라 값이 달라짐. 보통 인증 후에 User 객체 저장
    • Credentials : 비밀번호 등
    • Authorities : 권한 리스트

SecurityContext

  • Spring Security는 SecurityContext를 사용해 인증정보를 관리한다.
  • SecurityContextThreadLocal 변수에 담겨 1 요청 == 1 스레드 내에서 공유된다.
  • SecurityContext 자체는 특별한 기능 없이 Authentication 객체를 Wrapping 해주는 역할임
ThreadLocalSecurityContextHolderStrategy class
private static final ThreadLocal<SecurityContext> contextHolder = new ThreadLocal();

SecurityContextHolder

  • SecurityContextHolder에서는 해당 SecurityContext에 접근하여 조작해주는 역할을 함
    • SecurityContext get, set, clear 등등…
  • FilterChainProxy를 살펴보면 finally 블록에서 SecurityContextHolder.clearContext() 메소드를 호출한다.
    • Thread가 ThreadPool에 반환되기전 ThreadLocal 변수 값을 제거하기 위함


DefaultLoginPageGeneratingFilter

  • 로그인 페이지 html을 렌더링해주는 필터
DefaultLoginPageGeneratingFilter class

image

  • 기본 로그인 페이지 html을 이 클래스에서 생성하고 있음을 확인할 수 있음
  • 물론 로그인 페이지나 id/password parameter를 커스텀할 수 있다.
http.formLogin()
    .loginPage(커스텀URL)
    .usernameParameter()
    .passwordParameter()


Authentication

  • Spring Security에서 아이디/비밀번호를 사용한 인증절차는 아래와 같은 구조를 가진다.

image

로그인 인증

  • 어떤 사용자가 로그인을 시도했다고 가정했을 때, 아래와 같은 클래스들이 사용된다.

login drawio

  • 파란색은 인터페이스, 회색은 구현체이다.
  • AbstractAuthenticationProcessingFilter : 사용자 인증을 위한 토큰(Authentication 객체)를 생성함
    • UsernamePasswordAuthenticationToken을 생성
    • 여기서 권한 리스트 authorities는 null이다.
  • AuthenticationManager : 사용자 인증을 위한 Provider 리스트를 관리한다.
    • AuthenticationManager의 default 구현체는 ProviderManager
    • 실제 인증을 처리할 Provider는 토큰(Authentication 객체) 종류에 따라 결정된다.
    • UsernamePasswordAuthenticationToken일 경우 DaoAuthenticationProvider가 선택된다.
  • AuthenticationProvider : 실제 인증 로직을 처리하고, 최종 토큰을 생성한다.
    • 권한 리스트 authorities를 담는다

RememberMe 인증

  • RememberMe를 체크하고 로그인한 사용자가 나중에 다시 로그인할 경우

remember drawio

  • 쿠키를 파싱하여 정보를 받아온다.
  • 인증이 될때마다 토큰을 새로 생성한다.
.rememberMe()
    .key(키값)
    .tokenValiditySeconds(쿠키수명)
    .rememberMeParameter(파라미터이름)
    .rememberMeCookieName(쿠키이름)
    .alwaysRemember(bool값) // 활성화 여부
  • 여러 쿠키 설정을 커스텀할 수 있다.