Spring Security를 구현하고 사용하는데, 어떻게 인증이 진행되는지 모르고 코드만 따라치는 건 아무 의미가 없다. 어떻게 로그인이 되는지 정도는 간단하게 알고 가는 것이 기왕 공부하는 의미가 있지 않을까?
일반적인 클라이언트 - 서버 간 소통은 클라이언트가 뭔가 요청을 쏴주면 서버에서 해당 요청을 받고 이에 맞는 적절한 작업을 통해 응답하는 과정이다. 그런데 인증 / 인가가 추가되면 어떨까? 서버는 클라이언트의 모든 요청을 그냥 받고 수행해서 결과물을 반납할까? 그럼 인증 / 인가의 의미가 없지 않을까? 그럼, 나한테 요청을 보낸 사용자를 인증하는 과정은 어디서 일어나야할까?
해당 과정은 서버가 요청을 받아들이고 일련의 업무를 수행하기 전에 처리되어야 한다. 그러니까 클라이언트 - 서버의 일대일 소통 사이에 뭔가 하나가 요청을 가로채서 이 요청이 적절한지를 미리 검증하고, 적절하다면 해당 사용자의 정보와 요청을 함께 서버에 보내는 것이다. 이러한 과정은 서블릿 필터에서 일어난다. 이러면 또 서블릿은 뭐고 필터는 뭔지에 대해 알아야 하는데... 이 부분은 직접 찾아보시기를 권장한다. 하나 힌트를 주자면, 그냥 빌드 파일 하나 실행시켰는데 도대체 어떻게 내가 지정한 도메인으로 요청이 들어오고, 나는 어떻게 누가 나한테 요청 보냈는지를 알아서 그 사람한테 원하는 자원을 반환하지? 의 이유를 고민하면 서블릿이 무엇인지에 접근할 수 있다. 아무튼, 인증 처리는 이런 서블릿 필터에서 일어난다.
Spring Security를 적용하면, 서블릿 필터 체인 중간에 인증 처리와 관련한 필터를 끼워넣을 수 있다. 인증 처리가 없을 때는 필터 체인을 따라 죽죽 진행되어 디스패처 서블릿에서 요청이 쏴지던 흐름 중간에 인증 필터를 끼워넣어 잠깐 인증을 처리하는 것이다. 그럼 인증 / 인가를 구현한다는 것은 무엇일까? 이제는 알 수 있다. 우리는 저 중간에 끼워넣어지는 필터를 구현하면 된다.
앞서 본 그림에서 Spring Security 필터 체인의 가장 처음 필터는 UserNamePasswordAuthenticationFilter다. 해당 필터에서 사용자의 로그인 요청을 받아서 본격적인 인증 처리를 시작한다. 순서대로 살펴보자.
- 사용자는 로그인 요청을 보낸다.
- UserNamePasswordAuthenticationFilter는 해당 요청에 담긴 Username과 Password를 바탕으로 Authentication을 만든다. 이 때 만들어진 Authentication은 아직 인증이 완료된 상태는 아니다.
- 만들어진 Authentication을 AuthenticationManager에게 전달한다. 만들어진 Authentication이 적합한지 인증을 요청하는 것이다. AuthenticationManager는 인터페이스다. 이를 구현한 구체 클래스가 ProviderManager다.
- AuthenticationManager는 인증 AuthenticationProvider에 Authentication을 넘겨 인증 처리를 맡긴다.
- AuthenticationProvider는 UserDetailsService를 통해 UserDetails를 조회한다. UserDetails는 데이터베이스 등의 저장소에 저장된 사용자의 Username과 사용자의 자격을 증명해 주는 Credential인 Password, 그리고 사용자의 권한 정보를 포함하고 있는 컴포넌트이다.
- Credential은 해당 사용자를 증명하기 위한 구체적인 수단을 의미한다. 일반적으로 비밀번호가 사용된다.
- 받아온 Authentication의 Username정보를 바탕으로 Credential 저장소에서 Credential을 조회한다.
- 조회한 Credential을 기반으로 UserDetails를 생성한다.
- 이 때 조회한 Credential에 담긴 비밀번호는 보통 암호화되어있다. 비밀번호를 암호화하지 않고 DB에 저장하지는 않을 것이다.
- 생성한 UserDetails를 AuthenticationProvider에 반환한다.
- 받아온 UserDetails에 담긴 비밀번호를 PasswordEncoder를 통해 디크립팅 해서 처음 주어진 Authentication에 담긴 비밀번호와 같은지 비교한다. 만일 같다면 인증 처리가 완료된 Authentication을 생성한다.
- 인증된 Authentication을 반환한다.
- 인증된 Authentication을 반환한다.
- 인증된 Authentication을 Security Context에 저장한다. 이후에는 저장된 Authentication을 사용해 Authentication이 포함된 요청이 오면 검증한다.
생각보다 별 것 없다. 길~게 늘였지만 세 줄 요약을 해보자.
- 사용자가 아이디, 비밀번호를 가지고 로그인 요청을 보낸다.
- 아이디, 비밀번호를 검증한다.
- 검증을 통과하면 다음에도 쓸 수 있게 저장하고, 아니면 거절한다.
우리가 쉽게 생각할 수 있는 로그인 로직이다. Spring Security를 사용하면, 이렇게 어려움 없이 로그인 로직을 구현할 수 있다.
'Programming > Study' 카테고리의 다른 글
@BeforeEach vs @BeforeAll - 한 테스트 클래스에 여러 개의 테스트가 있으면 반드시 동시에 돌려봐야 하는 이유 / @TestInstace (2) | 2023.12.08 |
---|---|
테스트를 실행은 하고 싶은데 빌드에서는 제외하고 싶을 때 (1) | 2023.12.07 |
Spring Security를 사용할 때 csrf.disable()을 사용해도 되는 이유 - 토큰 사용 / 그래서 토큰은 어떻게 저장할건가? (2) | 2023.12.05 |
PasswordEncoder의 작동 원리와 테스트하기 어려운 이유 (0) | 2023.12.04 |
Querydsl 사용해보기 - 검색 기능 만들기 (1) | 2023.11.30 |
댓글