
: 스프링 부트를 활용한 애플리케이션 개발 실무
📝 목차
13장. 서비스의 인증과 권한 부여
13-1. 보안 용어 이해
- 인증
- 인가
- 접근 주체
13-2. 스프링 시큐리티
13-3. 스프링 시큐리티 동작 구조
13-4. JWT
- JWT의 구조
- JWT 디버거 사용하기
13-5. 스프링 시큐리티 JWT 적용
- UserDetails와 UserDetailsService 구현
- JwtTokenProvider 구현
- JwtAuthenticationFilter 구현
- SecurityConfiguration 구현
- 커스텀 AccessDeniedHandler, AuthenticationEntryPoint 구현
- 회원가입과 로그인 구현
- 스프링 시큐리티 테스트
13-6. 정리
보안과 관련된 용어와 개념을 알아보고,
스프링에 보안을 적용할 때 사용하는 스프링 시큐리티에 대해 알아보자!
: 사용자가 누구인지 확인하는 단계
☑️ 인증의 대표적인 예시 = 로그인
로그인 : 데이터베이스에 등록된 아이디와 패스워드를
사용자가 입력한 아이디와 비밀번호를 비교해서 일치여부를 확인하는 과정
로그인에 성공하면, 애플리케이션 서버는 응답으로 사용자에가 토큰(token) 전달
로그인에 실패한 사용자는 토큰을 전달받지 못해 원하는 리소스에 접근 불가
: 인증을 통해 검증된 사용자가 애플리케이션 내부의 리소스에 접근할 때, 사용자가 해당 리소스에 접근할 권리가 있는지를 확인하는 과정
일반적으로 사용자가 인증 단계에서 발급받은 토큰은 인가 내용을 포함
사용자가 리소스에 접근하면서 토큰을 함께 전달하면,
애플리케이션 서버는 토큰을 통해 권한 유무 등을 확인해 인가를 수행한다.
: 애플리케이션의 기능을 사용하는 주체를 의미
접근 주체는 사용자가 될 수도 있고, 디바이스, 시스템 등이 될 수도 있다.
✅ 애플리케이션은 인증 과정을 통해 접근 주체가 신뢰할 수 있는지 확인
인가 과정을 통해 접근 주체에게 부여된 권한을 확인
: 인증, 인가 등의 보안 기능을 제공하는 스프링 하위 프로젝트 중 하나
: 서블릿 필터(Servlet Filter)를 기반으로 동작
DispatcherServlet 앞에 필터가 배치돼 있습니다.

☑️ 필터체인(FiletChain)
: 서블릿 컨테이너에서 관리하는 ApplicationFilterChain을 의미
클라이언트에서 애플리케이션으로 요청을 보내면 서블릿 컨테이너는 URI를 확인해서 필터와 서블릿을 매핑
스프링 시큐리티는 사용하고자 하는 필터체인을 서블릿 컨테이너의 필터 사이에서 동작시키기 위해 DelegatingFilterProxy를 사용

☑️ DelegatingFilterProxy
: 서블릿 컨테이너의 생명주기와 스프링 애플리케이션 컨텍스트 사이에서 다리 역할을 수행하는 필터 구현체
표준 서블릿 필터를 구현하고 있으며,
역할을 위임할 필터체인 프록시(FilterChainProxy)를 내부에 가지고 있다. 필터체인 프록시는 스프링 부트의 자동설정에 의해 자동 생성 된다.
☑️ 필터체인 프록시(FilterChainProxy)
필터체인 프록시는 스프링 시큐리티에서 제공하는 필터이고,
보안 필터 체인(SecurityFilterChain)을 통해 많은 보안 필터를 사용할 수 있다.
☑️ 보안필터 체인 (SecurityFilter)
필터체인 프록시에서 사용할 수 있는 보안 필터 체인은 List 형식으로 담을 수 있게 설정돼 있어 URI 패턴에 따라 특정 보안필터 체인을 선택해서 사용한다.
보안필터 체인에서 사용하는 필터는 여러 종류가 있으며,
각 필터마다 실행되는 순서가 다르다.
✅ 보안필터 체인은 WebSecurityConfigureAdapter 클래스를 상속받아 설정
필터체인 프록시는 여러 보안 필터체인을 가질 수 있다.
여러 보안 필터체인을 만들기 위해서는 WebSecurityConfigureAdapter 클래스를 상속받는 클래스를 여러 개 생성하면 된다.
WebSecurityConfigureAdapter 클래스에는 @Order 어노테이션을 통해 우선순위가 지정되어 있다. 2개 이상의 클래스를 생성했을 때 똑같은 설정으로 우선순위가 설정돼 있으면 예외가 발생한다.
➡️ 상속받은 클래스에서 @Order 어노테이션을 지정해 순서를 정의해야 함
별도의 설정이 없다면, SecurityFilterChain에서 사용하는 필터 중
UsernamePasswordAuthenticationFilter를 통해 인증을 처리한다.
⬇️ UsernamePasswordAuthenticationFilter를 통한 인증과정

1️⃣ 클라이언트로부터 요청 ⭢ 서블릿 필터 ⭢ SecurityFilterChain으로 작업이 위임
그 중 UsernamePasswordAuthenticationFilter에서 인증을 처리한다.
2️⃣ AuthenticationFilter는 요청 객체(HttpServletRequest)에서
username과 password를 추출해서 토큰을 생성한다.
3️⃣ AuthenticationManager에게 토큰을 전달한다.
AuthenticationManager는 인터페이스이며,
일반적으로 사용되는 구현체는 ProviderManager이다.
4️⃣ ProviderManager는 인증을 위해 AuthenticationProvider로 토큰을 전달한다.
5️⃣ AuthenticationProvider는 토큰의 정보를 UserDetailsService에 전달한다.
6️⃣ UserDetailsService는 전달받은 정보를 통해
데이터베이스에서 일치하는 사용자를 찾아 UserDetails 객체를 생성한다.
7️⃣ 생성된 UserDetails 객체는 AuthenticationProvider로 전달되며,
해당 Provider에서 인증을 수행하고 성공하게 되면
ProviderManager로 권한을 담은 토큰을 전달한다.
8️⃣ ProviderManager는 검증된 토큰을 AuthenticationFilter로 전달한다.
9️⃣ AuthenticationFilter는 검증된 토큰을
SecurityContextHolder에 있는 SecurityContext에 저장한다.
스프링 시큐리티에 대한 자세한 설명은 공식 문서 참고
https://docs.spring.io/spring-security/site/docs/5.5.3/reference/html5/
: 당사자 간에 정보를 JSON 형태로 안전하게 전송하기 위한 토큰
URL로 이용할 수 있는 문자열로만 구성돼 있으며, 디지털 서명이 적용돼 있어 신뢰할 수 있다.
JWT는 주로 서버와의 통신에서 권한 인가를 위해 사용된다.
URL에서 사용할 수 있는 문자열로만 구성 ⭢ HTTP 구성요소 어디든 위치O
: JWT는 점( . )으로 구분된 세 부분으로 구성된다.
JWT의 일반적인 형식
xxxxx . yyyyy . zzzzz

두 가지 정보를 포함한다.
1. alg 속성 : 해싱 알고리즘을 지정
2. typ 속성 : 토큰의 타입을 지정
크게 세 가지 속성으로 분류 , 이 곳에 포함된 속성들은 클레임(Claim)이라 한다.
✅ iss
: JWT의 발급자 주체(Issuer)
✅ sub
: JWT의 제목(Subject)
✅ aud
: JWT의 수신인(Audience)
JWT를 처리하려는 각 주체는 해당 값으로 자신을 식별해야 한다.
요청을 처리하는 주체가 aud 값으로 자신을 식별하지 않으면 JWT는 거부된다.
✅ exp
: JWT의 만료시간(Expiration)
시간은 NumbericDate 형식으로 지정
✅ nbf
: Not Before을 의미
✅ iat
: JWT가 발급된 시간(Issued at)
✅ jti
: JWT의 식별자(JWT ID) , 주로 중복 처리를 방지하기 위해 사용
공개 클레임 (Public Claims)
: 공개 클레임은 키 값을 마음대로 정의 할 수 있다.
비공개 클레임 (Private Claims)
: 통신 간에 상호 합의 되고 등록된 클레임과 공개된 클레임이 아닌 클레임을 의미
: 인코딩된 헤더, 인코딩된 내용, 비밀키, 헤더의 알고리즘 속성 값을 가져와 생성된다.
: JWT 공식 사이트에서 JWT를 생성해 볼 수 있다.
