현재 이 강의 안에서
Spring Security 내부 흐름과
관련된 다양한 구성 요소에 대한
좋은 이해를 가지고 있을 것이라고 생각합니다
또는 Spring Security 필터
AuthenticationManager (인증 관리자) 및
AuthenticationProviders의 역할에 대해도
명확한 이해를 가지고 있을 것이라고 생각합니다
하지만 여기서
UserDetailsManager와 UserDetailsService의 역할이
무엇인지에 대한 의문이 있을 수 있습니다
따라서 당연히 이러한 구성 요소에 집중하면서
그게 어떤 역할을 하는지에 대해 얘기해보겠습니다
하지만 그 전에
한 번 더 강조하고 싶은것은
PasswordEncoder는 비밀번호를 다루는 데에만 관여하며
해당 비밀번호를 일반 텍스트로 다룰지
해싱하거나 암호화된 값으로
다룰지에 대한 것입니다
그것이 PasswordEncoder의 목적이며
우리는 다가오는 섹션에서 이에 대해
더 이야기 할 것입니다
이전 섹션에서 언급한 대로
기본적으로 Spring Security에서는
DaoAuthenticationProvider라는 이름의
AuthenticationProvider가 제공되며
이 AuthenticationProvider는
Spring Security 프레임워크 내에서 사용 가능한
UserDetailsManager 및
UserDetailsService 목록에서
도움을 받습니다
그러니 이제 UserDetailsManager와
UserDetailsService가 무엇인지
그리고 이 두 가지가 하는 역할에 대해
깊이 파고들어 보겠습니다
다음 슬라이드로 넘어가겠습니다
여기에서 볼 수 있듯이
가장 처음에 있는 인터페이스는
UserDetailsService입니다
이 서비스에는 loadUserByUsername이라는 이름의
추상 메소드가 있을 것입니다
예를 들어 수행하려는
모든 인증 작업을 생각해보면
가장 먼저
수행하려는 작업은
저장 시스템 내에 있는
유저 세부 정보 및
브라우저에 입력한 엔드 유저의 세부 정보를
로드하려는 것입니다
이것이 매우 일반적인 시나리오이기 때문에
Spring Security 팀이 수행한 것은
loadUserByUsername이라는 이름의
단일 추상 메소드를 가진 별도의 인터페이스를
만드는 것입니다
그리고 여기에서 왜 우리는 유저 세부 정보를
저장 시스템에서 유저 이름만으로 로드하는 것이며
왜 유저 이름과 비밀번호 둘 다가 아닌가
의문이 생길 수 있습니다
여기에는 두 가지 이유가 있습니다
첫 번째 이유는 다음과 같습니다
비밀번호를 불필요하게 네트워크로 전송해서는
안 된다는 것입니다
웹 조건 및 SQL 문에서
비밀번호를 사용하기 시작하면
유저의 실제 비밀번호를
데이터베이스 서버와
데이터베이스의 잠금에 전송하게 되는데
이는 권장되지 않는
방식입니다
그래서 Spring Security가 권장하는 것은
먼저 유저 이름을 사용하여
유저 세부 정보를 로드하는 것입니다
그리고 나중에 비밀번호를 비교하는
논리를 추가할 수 있고
그에 따라 인증이 성공했는지
여부에 따라 조치를 취할 수 있습니다
그리고 이 인터페이스 이후
UserDetailService를 확장하는 또 다른
인터페이스가 있습니다
그건 바로 UserDetailsManager입니다
이름 자체처럼 매우 적절합니다
이 인터페이스는 유저 세부 정보를
관리하는 데 도움이 될 것입니다
데이터베이스나 저장 시스템에서
세부 정보를 로드하는 것 외에도
때로는 새로운 유저를 생성하거나
유저 세부 정보를
업데이트하거나 삭제하거나
비밀번호를 변경하고 싶을 수 있습니다
따라서 이러한 시나리오를 수용하려면
UserDetailsManager 인터페이스가
유저 생성, 유저 업데이트
유저 삭제, 비밀번호 변경 및 유저 존재 여부와 같은 모든 이러한
메소드를 포함하고 있습니다
그리고 물론
UserDetails 인터페이스로부터
loadUserByUsername 메소드를 상속받습니다
그리고 Spring Security 팀은
단순히 인터페이스를 정의하고
개발자들에게 자체 로직을
작성하도록 맡기지 않고
여기에서 멈추지 않았습니다
대신 그들이 한 일은
UserDetailsManager의 일부 샘플 구현을
생성한 것입니다
따라서 이러한 샘플 구현은
이전 강의에서 사용한 InMemoryUserDetailsManager와
같은 것입니다
그리고 두 번째로 JdbcUserDetailsManager가 있으며
이를 사용하여 데이터베이스에서
유저 세부 정보를 검색할 수 있습니다
따라서 인증 중에
데이터베이스를 다룰 때는
단순히 JdbcUserDetailsManager를 사용할 수 있습니다
그리고 비슷하게 유저 세부 정보를
저장하기 위해 Ldap 서버를 사용하는 경우
LdapUserDetailsManager를 사용할 수 있습니다
이러한 것들이 Spring Security 프레임워크에서
제공하는 세 가지 중요한 구현 클래스입니다
그리고 많은 부분에서
이를 활용할 수 있습니다
하지만 자체 인증 로직이 있거나
모든 것을 직접 작성하려는 경우
확실히 할 수 있는 것은
자체 AuthenticationProvider를 정의하는 것입니다
Authentication Provider 내에서는
자체 로직을 작성할 수 있습니다
하지만 현재는
DaoAuthenticationProvider라는 기본 AuthenticationProvider를 사용하고 있으며
즉 DaoAnthenticationProvider입니다
이는 InMemoryUserDetailsManager
JdbcUserDetailsManager 및 LdapUserDetailsManager와 같은
UserDetailsManager 및 UserDetailsService의
구현에서 도움을 받고 있습니다
그래서 이를 통해 어느 정도 감을 잡으셨을 것으로 생각됩니다
이 모든 인터페이스와 클래스는
유저 세부 정보를 로드하고
저장하며
업데이트하는 데 도움을 줍니다
하지만 여기서 유저 세부 정보를
어떻게 표현할 수 있을까 와 같은 의문이 생길 수 있습니다
그래서 여기에 UserDetails라는
또 다른 인터페이스가 있습니다
다시 말해 이 인터페이스는 슬라이드 맨 위의
모든 인터페이스와 클래스에서
활용되는 인터페이스입니다
UserDetails는
저장하고 저장 시스템에서
로드하려는 엔드 유저의
세부 정보를 나타내는
인터페이스입니다
그리고 UserDetails는 인터페이스이기 때문에
Spring Security 팀은
또한 이 인터페이스의 구현 중 하나인
User 클래스를
제공했습니다
이전 섹션에서도 User 및
UserDetails를 사용했지만
이러한 인터페이스 그리고 클래스들이
Spring Security 내에서 수행하는
역할에 대한 혼란이 없도록
모든 세부 사항을 다룰 것입니다
제가 제공한
Spring Security 내부의
중요한 인터페이스 그리고
클래스에 대한 소개에 대해
명확하게 이해하셨기를 바랍니다
빠르게 웹 애플리케이션 내에서
시나리오를 실행하여 모든 토론과 이해를
신속하게 검증해 봅시다
그래서 지금 이 순간부터
보시다시피 우리는 UserDetailsManager
Bean을 생성하고 구축했습니다
그래서 UserDetailsManager Bean을
생성하고 구축할 때마다
DaoauthenticationProvider는
InMemoryUserDetailsManager 내에 있는
메소드를 호출하여
사용자를 인증하려고 할 것입니다
그래서 호출할 메소드는
loadUserByUsername이며
이 메소드의 반환 유형은 UserDetails입니다
물론 이 메소드는
UserDetailService라는 인터페이스에 의해 오버라이딩 되었습니다
먼저 createUser, updateUser와 같은
모든 메소드를 포함한
UserDetailsManager를 구현하고 있습니다
그리고 이 인터페이스는 내부적으로
또 하나의 인터페이스인 UserDetailService를 확장하고 있는데
이 인터페이스는
loadUserByUsername이라는 단일 메소드를 가지고 있습니다
그럼 loadUserByUsername 내부에
중단점을 설정하여
빠르게 검증해 보겠습니다
그래서 여기에 중단점을 두었습니다
이제 브라우저로 이동하여
웹 애플리케이션의 메모리에
생성한 유저 세부 정보로
로그인을 시도해 보겠습니다
브라우저로 이동했습니다
보안 API 하나인
Mycards에 접근해보겠습니다
내 자격 증명을 입력해 보겠습니다
유저 이름은 admin이고 비밀번호는 12345입니다
로그인을 클릭하자마자
loadUserByUsername 메소드 내에서
중단점이 멈춘 것을
확인할 수 있습니다
이 메소드의 호출 계층 구조를 확인하면
이 호출이
DaoAuthenticationProvider에서
발생하는 것을 볼 수 있습니다
물론 DaoAuthenticationProvider에
대한 호출은 AuthenticationManager의
구현인 ProviderManager에서 발생합니다
그리고 ProviderManager 이전에는
우리의 요청을 처리하기 위해
상당한 수의 필터가 참여하며
이 필터들은 ProviderManager를 거쳐
DaoAuthenticationProvider를 거쳐
InMemoryUserDetailsManager에 이르고 있습니다
따라서 이를 통해
우리는 이야기한 내용이
정확하다는 확신을 가지고 있습니다
Spring Security 내부 흐름을 확인하면
제 DaoAuthenticationProvider는
UserDetailsManager의 구현 중 하나인
InMemoryUserDetailsManager를 활용하고 있습니다
InMemoryUserDetailsManager를 사용하는 이유는 무엇일까요?
그건 코드 내에서
InMemoryUserDetailsManager 유형의
Bean을 생성했기 때문입니다
그리고 그 안에 모든 필요한 유저를 정의했습니다
그러니 이해하셨기를 바랍니다
다음 몇 강의 동안에는
이러한 인터페이스들에 대해
깊이 알아볼 것입니다
그러니 이 이론적인 논의를
조금만 더 참아주시기 바랍니다
왜냐하면 매우 가치 있는 논의이기 때문입니다
그래서 절대 건너 뛰어서는 안 됩니다
이를 통해 Spring Security 프레임워크에 대한
완전한 그림을 그릴 수 있고
이 프레임워크의 마스터가 될 것입니다
감사드리며 다음 강의에서 뵙겠습니다
수고하셨습니다