최근에 프로그래머스에서 운영하는 '웹 백엔드 시스템 구현 스터디'에서 스프링을 학습하고 있다. 혼자 공부하면 어려운 부분을 다뤄줘서 인사이트를 넓힐 수 있었다. 2주차 세션에서 스프링시큐리티를 다뤄 정리하고자 한다.
우리는 애플리케이션을 만들다 보면 인증, 권한이 필요한 시점이 온다. 애플리케이션 개발자들은 ID, PASSWORD를 입력받아서 서버 혹은 클라이언트의 상태를 통하여 세션을 유지할 생각을 해본다.
그런데 애플리케이션 개발자가 직접 로그인처리를 하면 되지 않나!? 왜 스프링시큐리티를 굳이 사용해야 할까?
Spring Security는 엔터프라이즈 애플리케이션에 대한 인증, 권한 부여 및 기타 보안 기능을 제공하는 Java / Java EE 프레임 워크입니다.
스프링 시큐리티는 위키에선 이렇게 정의되어 있다. 단순 인증/권한처리만 하는 게 아닌 CSRF같은 보안이슈도 시큐리티단에서 처리할 수 있다. 또 ID/PASSWORD로만 로그인할 수 있는 상황이 아닌, OAuth2.0 등을 지원하여 다양한 방법의 로그인들을 지원한다.
즉 애플리케이션 프로그래머는 인증/인가가 잘 추상화되어있는 시큐리티를 적용하면, 쉽게(쉬운진 잘 모르겠다.) 인증/인가 처리할 수 있고, 웹 보안이슈도 해소할 수 있다.
또 권한을 URI기준으로 처리하여, 인증방법이 바뀌거나 추가되어도 인증 외에는 변경되지 않는 장점이 있다.
되게 좋아 보인다..! 스프링 시큐리티가 어떤 구조인지 알아보자.
인증은 참이라는 근거가 있는 무언가를 확인하거나 확증하는 행위이다.
사용자의 Identification을 확인하는 절차이다.
보통 ID와 PASSWORD를 통해서 서버에게 요청을 보내, 올바른 유저인지 서버는 응답한다.
ex) 로그인
인가란 리소스에 대한 접근 권한 및 정책을 지정하는 기능이다
ex) 관리자 페이지 접근, 게시판 글쓰기 등에서 보통 인가절차를 밟는다. 우리가 로그인 이후, 해당 리소스를 접근할 수 있는 건. 보통 로그인되어있음을 Session에 저장하거나, JWT 토큰을 이용한다. 그래서 사용자는 로그인이되어있음을 느낄 수 있다. 인증이 선행되는 걸 알 수 있다.
권리나 권력 또는 직권이 미치는 범위.
Request한 유저의 권한을 검사한다. 인가절차에서 요소로 사용된다.
ex) 관리자 페이지를 접근할 때, Request한 유저가 관리자인지 확인한다.
스프링 시큐리티는 필터 기반이다. 주요 로직들은 모두 필터를 거치고 컨트롤러 단에 닿을 수 있다.
위 사진은 스프링 MVC의 Request 처리 과정이다.
Filter를 거치고, Dispatcher Servlet을 거친다. 그 후에서야 컨트롤러를 찾는 과정을 볼 수 있다.
사진으로 알 수 있는 건 스프링시큐리티는 디스패처 서블릿에 도달하기 전에 로직을 수행하는 걸 알 수 있다. (Filter는 J2EE 표준스펙으로 Spring이 아니어도 Servlet Filter를 이용할 수 있다.)
시큐리티에는 여러 Filter가 존재하며, 각 책임에 따른 필터들을 순서대로 처리 후에 DispatcherSelvet으로 보낸다.
필터는 1개만 등록시킬 수 있는게 아닌, 필터체인으로 시큐리티에 등록된 순서대로 로직이 처리된다.
스프링시큐리티를 Enable하면 위 같은 필터들이 위에서 아래로 동작한다.
우린 위에서 UsernamePassAuthenticationFilter
를 활용해보려고 한다.
클래스가 어떤 역할을 하는지 알아보자.
UsernamePassAuthenticationFilter
Authentication
AuthenticationManager
인증을 담당한다. 위 라이프사이클에선 UsernamePassAuthenticationFilter
이 AuthenticationManager
을 호출하여, 해당 Authentication객체가 유효한지 검증한다.
인증 순서
처음에 요청이 들어오면 AuthenticationFilter(UsernamePassAuthenticationFilter)를 거친다.
우리는 요청에 따른 UsernamePasswordAuthenticationToken을 생성한다. (Authentication 인터페이스의 구현체다.)
UsernamePasswordAuthenticationToken(Token이라고 하겠다.)을 AuthenticationManager에게 이 Token은 옳바른 유저인지 물어본다.
AuthenticationManager는 1개 이상의 Provider를 갖고 있는데, Provider는 Token(Authentication의 구현체) 객체를 적절히 판단하여 인증처리를 한다.
우리가 직접 구현한 서비스에 해당 유저에게 인증요청을 보낸다.
인증된 유저라고 판단되면 적절한 User DTO객체를 전달한다.
인증된 결과를 SecurityContextHolder에 저장한다.
기본적으로 스프링 시큐리티가 무엇인지, 또 인증이 어떻게 진행되는지 알아봤다.
사실 인증절차가 매우 가볍게 지나갔는데, 더 보완하고 싶다.
다음 포스팅은 시큐리티에서 어떻게 인가처리되는지 적어보려고 한다.