본문 바로가기

Development/Spring

[Spring] 인증과 권한 부여, Spring Security

보안 용어 이해

인증(authentication)

  • 인증은 사용자가 누구인지 확인하는 단계이다.
  • 예를 들어, 로그인은 데이터베이스에 등록된 아이디와 패스워드를 사용자가 입력한 아이디와 패스워드와 비교하여 일치 여부를 확인하는 인증 과정이다.
  • 토큰 인증 방식에서 로그인에 성공하면 애플리케이션 서버는 응답으로 사용자에게 토큰(Token)을 전달한다. 로그인에 실패한 사용자는 토큰을 전달받지 못해 원하는 리소스에 접근할 수 없게 된다.
  • 세션 방식 로그인 방식에서 서버는 일반적으로 토큰 대신 세션 ID를 사용자에게 전달한다.

인가(Authorization)

  • 인가는 인증을 통해 검증된 사용자가 애플리케이션 내부의 리소스에 접근할 때 사용자가 해당 리소스에 접근할 권리가 있는지를 확인하는 과정을 의미한다.
  • 예를 들어, 로그인한 사용자가 특정 게시판에 접근해서 글을 보려고 하는 경우 게시판 접근 등급을 확인해 접근을 허가하거나 거부하는 것이 대표적인 인가의 사례이다.
  • 일반적으로 사용자가 인증 단계에서 발급받은 토큰은 인가 내용을 포함하고 있으며, 사용자가 리소스에 접근하면서 토큰을 함께 전달하면 애플리케이션 서버는 토큰을 통해 권한 유무 등을 확인해 인가를 수행한다.
  • 세션 인증 방식에서는 서버는 생성된 세션 ID를 쿠키 또는 HTTP 헤더에 담아 사용자에게 전송하고, 사용자는 요청에 세션 ID를 포함하여 서버에 인증 정보를 전달한다. 그 후 서버는 세션 ID를 통해 사용자 정보를 확인하고 요청을 처리한다.

접근 주체(Principal)

  • 접근 주체는 말 그대로 애플리케이션 기능을 사용하는 주체를 의미한다.
  • 접근 주체는 사용자가 될 수도 있고, 디바이스, 시스템 등이 될 수도 있다.
  • 애플리케이션은 인증 과정을 통해 접근 주체가 신뢰할 수 있는지 확인하고, 인가 과정을 통해 접근 주체에게 부여된 권한을 확인하는 과정 등을 거친다.

스프링 시큐리티(Spring Security)

  • 스프링 시큐리티(Spring Security)는 애플리케이션의 인증, 인가 등의 보안 기능을 제공하는 스프링 하위 프로젝트 중 하나이다.
  • 보안과 관련된 많은 기능을 제공하기 때문에 스프링 시큐리티를 활용하면 더욱 편리하게 원하는 기능을 설계할 수 있다.

스프링 시큐리티의 동작 구조

스프링 시큐리티는 서블릿 필터(Servlet Filter) 를 기반으로 동작하며, 다음과 같이 DispatcherServlet 앞에 배치돼 있다.

 

위 그림의 필터체인(FilterChain)은 서블릿 컨테이너에서 관리하는 ApplicationFilterChain을 의미합니다. 클라이언트에서 애플리케이션으로 요청을 보내면 서블릿 컨테이너는 URI를 확인해서 필터와 서블릿을 매핑합니다.

스프링 시큐리티는 사용하고자 하는 필터체인을 서블릿 컨테이너의 필터 사이에서 동작시키기 위해 다음과 같이 DelegatingFilterProxy를 사용합니다.

 

DelegatingFilterProxy

 

이미지 출처: https://prod-acb5.kxcdn.com/wp-content/uploads/2020/06/FilterChainProxy.png

  • DelegatingFilterProxy는 서블릿 컨테이너의 생명주기와 스프링 애플리케이션 컨텍스트(Application Context) 사이에서 다리 역할을 수행하는 필터 구현체이다.
  • 표준 서블릿 필터를 구현하고 있으며, 역할을 위임할 필터체인 프록시(FilterChainProxy)를 내부에 가지고 있다.

필터체인 프록시(FilterChainProxy)

  • 필터체인 프록시는 스프링 부트의 자동 설정에 의해 자동 생성된다.
  • 스프링 시큐리티에서 제공하는 필터로서 보안 필터체인(SecurityFilterChain)을 통해 많은 보안 필터(Security Filter)를 사용할 수 있다.
  • 필터체인 프록시에서 사용할 수 있는 보안 필터체인은 List 형식으로 담을 수 있게 설정돼 있어 URI 패턴에 따라 특정 보안필터 체인을 선택해서 사용하게 된다.
  • 보안필터 체인에서 사용되는 필터는 여러 종류가 있으며, 각 필터마다 실행되는 순서는 다르다.

UsernamePasswordAuthenticationFilter를 통한 인증 수행 과정

  1. 클라이언트로부터 요청을 받으면 서블릿 필터에서 SecurityFilterChain으로 작업이 위임되고, 그중 UsernamePasswordAuthenticationFilter(위 그림에서 AuthenticationFilter)에서 인증을 처리
  2. AuthenticationFilter는 요청 객체(HttpServletRequest)에서 username과 password를 추출해서 토큰을 생성함
  3. AuthenticationManager에게 토큰을 전달한다. AuthenticationManager는 인터페이스로, 일반적으로 사용되는 구현체는 ProviderManager이다.
  4. ProviderManager는 인증을 위해 AuthenticationProvider로 토큰을 전달한다.
  5. AuthenticationProvider는 토큰 정보를 UserDetailsService로 전달한다.
  6. UserDetailsService는 전달받은 정보를 통해 DB에서 일치하는 사용자를 찾아 UserDetails 객체를 생성한다.
  7. 생성된 UserDetails 객체는 AuthenticationProvider로 전달되며, 해당 Provider에서 인증을 수행하고 성공하게 되면 ProviderManager로 권한을 담은 토큰을 전달한다.
  8. ProviderManager는 검증된 토큰을 AuthenticationProvider로 전달한다.
  9. AuthenticationFilter는 검증된 토큰을 SecurityContextHolder에 있는 SecurityContext에 저장한다.

위 과정에서 UsernamePasswordAuthenticationFilter는 접근 권한을 확인하고 인증이 실패할 경우 로그인 폼이라는 화면을 보내는 역할을 수행하는데, RESTful API를 구현하는 서버의 경우 로그인 폼 화면이 존재하지 않으므로 다른 필터에서 인증 및 인가 처리를 수행해야 한다.

참고

  • 스프링 부트 핵심 가이드 "스프링 부트를 활용한 애플리케이션 개발 실무" , 장정우, 2022