서비스의 인증과 권한 부여

김하영·2023년 7월 9일

출처: 스프링 부트 핵심 가이드 - 장정우 지음
https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=296591989

어플리케이션을 개발하다 보면 인증과 인가 등의 보안 기능을 추가해야 할 때가 있다.
이번 포스팅에서는 보안과 관련된 용어와 개념을 알어보고 스프링에 보안을 적용할 때 하용하는 스프링 시큐리티에 대해 알아보자!

화면이 없는 무상태 REST 어플리케이션에서는 로그인을 통한 일반적인 인증과 인가 방식이 아닌, 매 요청마다 토큰값을 활용하는 보안 기법을 사용하는데 이에 대해 알아보자!

보안 용어 이해

인증

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

인가

  • 인가(authorization)은 인증을 통해 검증된 사용자가 어플리케이션 내부의 리소스에 접근할 때, 사용자가 해당 리소스에 접근할 권리가 있는지를 확인하는 과정을 의미한다.
  • 예를들어 로그인한 사용자가 특정 게시판에 접근해서 글을 보려고 하는 경우, 게시판 접근 등급을 확인해 접근을 허가하거나 거부하는 것이 대표적인 인가의 사례이다.
  • 일반적으로 사용자가 인증 단계에서 발급받은 토큰은 인가 내용을 포함하고 있으며, 사용자가 리소스에 접근하면서 토큰을 함께 전달하면 어플리케이션 서버는 토큰을 통해 권한 유무 등을 확인해 인가를 수행한다.

접근 주체

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

스프링 시큐리티

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

스프링 시큐리티의 동작

  • 스프링 시큐리티는 서블릿 필터를 기반으로 동작하며 필터는 DispatcherServlet 앞에 배치되어 있다.
  • 위 그림에서 필터체인은 서블릿 컨테이너에서 관리하는 ApplicationFilterChain을 의미한다.
  • 클라이언트에서 어플리케이션으로 요청을 보내면 서블릿 컨테이너는 URI를 확인하서 필터와 서블릿을 매핑한다.
  • 스프링 시큐리티는 사용하고자 하는 필터체인을 서블릿 컨테이너의 필터 사이에서 동작시키위해 DelegatingFilterProxy를 사용한다.
  • DelegatingFilterProxy는 서블릿 컨테이너의 생명 주기와 스프링 어플리케이션 컨텍스트 사이에서 다리 역할을 하는 필터 구현체이다.
  • 필터체인 프록시는 스프링부터의 자동설정에 의해 자동 생성된다.
  • 필터체인 프록시는 스프링 시큐리티에서 제공하는 필터로서, SecurityFilterChain을 통해 많은 Security Filter를 사용할 수 있다.
  • 필터체인 프록시에서 사용할 수 있는 보안 필터 체인은 List형식으로 담을 수 있기 때문에 URI패턴에 따라 특정 보안 필터체인을 선택해서 사용하게 된다.
  • 보안 필터체인은 WebSecurityConfigurerAdapter클래스를 상속받아 설정할 수 있다.
  • 여러개의 보안 필터체인을 만들기 위해서는 WebSecurityConfigurerAdapter클래스를 상속받는 클래스를 여러개 생성하면 된다.
  • 여러개의 보안 필터체인을 만들때, WebSecurityConfigurerAdapter클래스에는 @Order 어노테이션을 통해 우선순위가 지정되어 있는데, 2개 이상의 클래스를 생성했을 때, 똑같은 설정으로 우선순위가 100이 설정되어 있으면 예외가 발생하므로 상속받은 클래스에서 @Order 어노테이션을 지정해 순서를 정의하는 것이 중요하다.
  • 별도의 설정이 없으면 스프링 시큐리티에서는 SecurityFilterChain에 사용하는 필터 중 UsernamePasswordAuthenticationFilter를 통해 인증을 처리한다.

<UsernamePasswordAuthenticationFilter를 통한 인증 처리 과정>

  1. 클라이언트로부터 요청을 받으면 서블릿 필터에서 SecurityFilterChain으로 작업이 위임되고 그 중 UsernamePasswordAuthenticationFilter(그림에서 AuthenticationFilter)에서 인증을 처리한다.

  2. AuthenticationFilter는 요청 객체(HttpServletRequest)에서 username과 password를 추출해서 토큰을 생성한다.

  3. AuthenticationManger에게 생성된 토큰을 전달한다. AuthenticationManager는 인터페이스이며, 일반적으로 사용되는 구현체는 ProviderManager이다.

  4. ProviderManager는 인증을 위해 AuthenticationProvider로 토큰을 전달한다.

  5. AuthenticationProvider는 토큰의 정보를 UserDetailsService에 전달한다.

  6. UserDetailsService는 전달받은 정보를 통해 데이터베이스에서 일치하는 사용자를 찾아 UserDetails객체를 생성한다.

  7. 생성된 UserDetails객체는 AuthenticationProvider로 전달되며, 해당 Provider에서 인증을 수행하고 성공하게 되면 ProviderManager로 권한을 담은 토큰을 전달한다.

  8. ProviderManager는 검증도니 토큰을 AuthenticationFilter로 전달한다.

  9. AuthenticationFilter는 검증된 토큰을 SecurityContextHoder에 있는 SecurityContext에 저장한다.

  • 위과정에서 사용된 UsernamePasswordAuthenticationFilter는 접근 권한을 확인하고 인증이 실패할 경우 로그인 폼이라는 화면을 보내는 역할을 수행한다.
  • 화면이 없는 RESTful 어플리케이션에서는 다른 필터에서 인증 및 인가 처리를 수행해야한다.
    => JWT토큰을 사용해 인증수행!!! JWT와 관련된 필터를 생성하고 UsernamePasswordAuthenticationFilter 앞에 배치해서 먼저 인증을 수행할 수 있게 설정하도록 하자
profile
백엔드 개발자로 일하고 싶어요 제발

0개의 댓글