이번 강의에서는
Spring Security 프레임워크에서 제공되는
UserDetailsManager 구현 클래스 속에
정확히 어떤 것들이 있는지 살펴 보겠습니다
보시다시피
대표적인 세 가지 구현을 나타냈습니다
따라서 이들이 가장 많이 쓰이고
UserDetailsManager 구현에서 가장 중요합니다
물론 UserDetailsManager 구현 클래스가
몇개 더 있긴 하지만
이 세 가지에 대해 배우면
전체적인 그림이 잡힐 것입니다
예를 들어 Spring Security 프레임워크 속
이 UserDetailsManager 구현 클래스의
목적이 무엇인지 알 수 있습니다
그럼 이제 Spring Security 프레임워크
코드에 대해 탐구하면서 배워 봅시다
이를 위해 IntelliJ IDEA로 들어가겠습니다
이제 구현 클래스를
탐구하기 전에
pom.xml에 몇 가지 dependencies을 추가해야 합니다
해당 dependencies들은 LDAP과 관련 있습니다
왜냐하면 우리는 LDAP UserDetailsManager 속에
무엇이 있는지에 대해 알아보고 싶기 때문입니다
기본적으로
단순히 이 spring-boot-starter-security를 스타터 프로젝트에 추가하면
Spring Security 프레임워크 코드 속에서는
찾을 수 없습니다
왜냐하면 가장 흔히 사용되는 유즈 케이스(use case)인
LDAP이 아니기 때문입니다
따라서 해당 spring-boot-starter-security 스타터 프로젝트에서는
찾아볼 수 없습니다
여기서 추가하고 싶은 dependencies은
두 가지입니다
하나는 spring-ldap-core
그리고 나머지 하나는 spring-security-ldap입니다
이 둘이 LDAP과 관련 있는 것들입니다
이제 LDAP과 관련된 최신 dependencies들이
Maven 프로젝트에 다운로드 되도록
해당 Maven을 새로고침 하겠습니다
다운로드가 완료될 때까지 기다리겠습니다
한편 이 InMemoryUserDetailsManager 속에는
뭐가 있는지 탐구해 보도록 하겠습니다
아시다시피 이는 UserDetailsManager의
구현 클래스입니다
이 속에 있는 각 메소드 안에는
정확히 어떤 일들이 일어나는지 알아보겠습니다
첫번째로 createUser 메소드를 보겠습니다
이 메소드는 누군가 이 클래스의 생성자를
호출하려고 할 때마다
호출됩니다
이전에 배운 내용 중
ProjectSecurityConfig에서는
웹 애플리케이션의 메모리 속에
새로운 특정 유저들을 생성할 때마다
이 클래스의 생성자에게 유저에 대한
정보를 보냈었습니다
따라서 이 클래스의 생성자를 클릭하면
보시다시피 제가 보냈었던 유저에 관한 정보에 대해
이 메소드는 호출될 것입니다
이 메소드에서는
users라는 이름의 맵 속에 유저에 대한 정보를
채워 나갑니다
따라서 초기에 이 맵은 비어있습니다
유저 정보를 생성하려할 때
해당 맵은 모든 유저에 대한 정보를
Username.LowerCaseCase라는 키에 담고, 이 값은
보냈던 유저에 대한 정보입니다
이상 createUser 속에 무엇이 있는지 살펴보았습니다
그리고 deleteUser의 경우
해당 코드는 특정 유저를 삭제하고 싶은
상황에서 실행됩니다 이는 지정된 키를
전달하여 HashMap에서 특정 기록이 삭제될 것입니다
updateUser의 경우에도 마찬가지입니다
이 값들이 업데이트 되는 것입니다
userExists 메소드를 보겠습니다
보시다시피 이는 단순히 블리언(Boolean) 값을 반환합니다
해당 사용자 이름을 가진 유저가 존재한다면
true로, 아니라면 false로 나타냅니다
changePassword의 경우도 마찬가지입니다
유저의 비밀번호를 변경하기 위해서는
꽤 많은 양의 로직이 필요함을 볼 수 있습니다
정보를 보고 쉽게 이해하실 수 있을 것입니다
여기서 다음으로 중요한 메소드를 체크할 것인데
loadUserByUsername입니다
이미 여러번 봐왔던 것입니다
이 메소드는 저장 시스템에서 유저에 대한
정보의 로딩을 담당합니다
여기서는 저장 시스템이 InMemory입니다
그리고 이 정보들은 공급자에게 전달되고
공급자는 비밀번호를 비교하여
그에 따른 성공적인
인증 정보 객체를 만들어낼 것입니다
여기서
"UserDetailsManager에는 여러 구형이 있는데
DaoAuthenticationProvider는 어떤 UserDetailsManager을
호출해야하는지 어떻게 아나요?"와 같은 의문이 들 수 있습니다
이에 대한 답변은 다음과 같습니다
ProjectSecurityConfig를 확인해 보면
여기에서 InMemoryUserDetailsManager
타입의 Bean을 생성했습니다
Jdbc 혹은 LDAP와 관련된 것은 만들지 않았습니다
따라서 이는 Spring 프레임워크와
Spring Boot에게 InMemoryUserDetailsManager 속에 있는
코드를 활용하라는 분명한 지시가 되겠습니다
제가 전달하고자 하는 바가 명확히 이해 되셨길 바랍니다
따라서 프로젝트 구성에서
정의한 Bean에 기반하여
인증 정보 공급자 중 하나에게서 호출되어
Spring Security 프레임워크에 의해
같은 매니저들이 사용될 것입니다
기본적으로 인증 정보 공급자는
DaoAuthenticationProvider가 되겠습니다
따라서 InMemory는 비프로덕션 애플리케이션
혹은 몇몇 데모 애플리케이션에서
가장 흔히 사용될 수 있습니다
따라서 Spring Security 팀에서
코드가 전부 제공되는 것입니다
우리는 원하는 유저 정보를
정의하고 저장하여
InMemoryUserDetailsManager의 Bean을
생성하면 됩니다
따로 작성해야 하는 코드는 없습니다
보시다시피 이 클래스에는 우리가 작성하지 않아도 되는
수백 줄의 코드가 있습니다
그리고 InMemory 인증 후
일어날 수 있는 가장 흔한 상황은
데이터베이스에서
인증을 수행하는 것입니다
이를 위해 하나의 구현 클래스가 더 있는데
이는 JdbcUserDetailsManager입니다
이 클래스는 정말 흥미롭습니다
따라서 여기에 노력을 쏟아 봅시다
데이터베이스에서 디테일을 로딩할 때마다
몇몇 의문점이 생기기 마련입니다
테이블 구조는 무엇인지
데이터베이스 구조는 무엇인지
열의 이름들은 어떻게 되는지
어디에 유저 정보를 저장하고 싶은지 등등입니다
이에 대한 대답은 다음과 같습니다
기본적으로 Spring Security 팀에서 데이터베이스 구조
테이블 구조, 열 등등 모든 구조를 설계하고
이러한 설계로 이 구현 클래스 속에
모든걸 코딩해 뒀습니다
여기에 보시다시피 이 loadUserByUsername이라는
메소드를 호출하면
보냈던 유저 이름을 기반으로
loadUserByUsername 메소드가 호출 됩니다
이 메소드 안에는 쿼리가 생성되고
이 쿼리에게 유저 이름이
SQL 쿼리 속 변할 수 있는 값으로 보내집니다
확인해 보면 이 쿼리가 사용될 것이고
이는 Spring Jdbc 템플릿의 도움을 받아
구성할 데이터베이스에 대해
쿼리를 실행할 것입니다
이 쿼리를 클릭해 보겠습니다
이 쿼리는 문자열이며
이 문자열을 검색하려고 하면 상수(고정 값)의 값을 가져오게 됩니다
따라서 해당 값을 클릭하면
이는 실행할
select 쿼리입니다
select username, password, enabled
from users, where username 은 어떠한 값이 됩니다
따라서 이는 테이블의 이름이 유저여야 함을 알 수 있습니다
그렇지 않으면
JdbcUserDetailsManager에 의해
확장된 JdbcDaoImpl 속에 있는 이 코드는 작동하지 않습니다
따라서 이 상수 안에 있는
기본 스키마를 살펴보면
오른쪽으로 스크롤하면
이 스키마 파일이 Spring Security가
JdbcUserDetailsManager를 활용할 때마다 사용할
테이블 정보와 열 정보를 다 가지고 있습니다
이 안에 정확히 무엇이 있는지 확인해 보도록 합시다
Spring Security 프레임워크 안에 있는
users.ddl을 열어보면
primary key인 유저 이름
비밀번호, 활성화된 불리언(Boolean) 값과 같은
유저 정보를 저장하는 users 테이블과 관련된
스크립트를 볼 수 있습니다
이게 테이블이 갖게 될
중요한 세 열입니다
그리고 Spring Security가 예상하는
데이터베이스 속 또 다른 테이블은
주어진 유저 이름에 지정하고자 하는 권한 값이 무엇인지에 대한 것이고
users 테이블로 향하는 외부 링크가 있습니다
따라서 authority는 유저에 관한
권한 정보를 저장합니다
따라서 이 두 테이블이 있으면
JdbcUserDetailsManager를 잘 활용할 수 있겠습니다
여기 안에는 다양한 종류의 메소드가 있습니다
예를 들어 UI 애플리케이션에서
유저를 생성하고 싶을 때마다
이 메소드를 사용하여 데이터베이스 안에
유저를 생성할 수 있습니다
createUserSql을 사용해 보면
insert 문장(statement)이 users 테이블 속에 있습니다
삭제(delete), 업데이트(update)에도 똑같이 적용 됩니다
이 부분은 꽤 쉽습니다
유저와 권한 외에도
GroupManager 인터페이스가 있음을 볼 수 있습니다
GroupsManager의 도움으로 그룹을 생성하고
유저들을 이러한 그룹으로 지정할 수 있습니다
때로는 유저에게 하나의 권한만을 지정하는 것은
충분하지 않을 수도 있습니다
우리가 원하는 것은 그룹으로 권한들을
묶어 사용하려고 하는 것입니다
이러한 상황들에서는
이 JdbcUserDetailsManager 속에 있는
그룹들을 활용하여
그룹들을 생성하고
유저들을 그룹으로 지정합니다
하지만 앞으로의 수업에서
인가에 대해 이야기할 때
권한, 역할, 역할 기반의 액세스 메커니즘을
논의할 예정이니
당장은 이 그룹들을 잠깐 무시해 주시기 바랍니다
현재로서는 Spring Security 프레임워크에 대해
확실히 이해하는 것이 중요합니다
기본적으로는 데이터베이스 구조를 설계하고
이를 기반으로 엔드 유저의 정보를 로딩
저장, 업데이트 삭제할 수 있는
코드를 갖고 있습니다
따라서 JdbcUserDetailsManager를 사용할 떄는
organization 데이터베이스 속 구조와
같은 구조를 따르는 것이
필수입니다
이에 대한 내용은 앞으로 JdbcUserDetailsManager를
활용하는 것에 대한 수업에서 다루겠습니다
그리고 탐구해 볼 다음 UserDetailsManager은
LdapUserDetailsManager입니다
다시 한번 말하지만 LdapUserDetailsManager은
흔하게 사용되는 구현 클래스는 아닙니다
왜냐하면 저장 시스템으로 LDAP 서버가 있지 않는 이상
이 UserDetailsManager를 사용하지 못할 수도 있기 때문입니다
하지만 이 내용을 이번 수업에 빠르게 진행해 보고
이것도 같은 구조를 따르는지
확인해 봅시다
여기서 loadUserByUsername를 찾아 보면
유저 정보를 설정했던
주어진 LDAP 서버에서
유저 정보를 로딩하기 위한
코드가 다 있음을 볼 수 있습니다
그리고 LDAP는 자주 사용되는 것이 아니기 때문에
익숙하지 않다고 해서 걱정할 것은 없습니다
LDAP와 Active Directory를 저장 시스템으로
사용하는 조직은 많지 않습니다
그러한 상황에서는 UserDetailsManager 속에 있는
코드를 활용하면 됩니다
LDAP에 대해 더욱 알아야하는
상황에 놓여진다면
LDAP와 관련된 강의를 수강하여
이 LdapUserDetailsManager 클래스를
활용하기를 추천합니다
이로써 구현 클래스에 대해
명확히 이해 하셨길 바랍니다
현재로서는 웹 애플리케이션의
메모리 위치 속에 유저를 전부 생성했습니다
다음 단계로
데이터베이스 안에 유저 정보를 전부 저장하고
정보를 데이터베이스에 전부 저장한 후
JdbcUserDetailsManager 클래스를 활용하여
인증을 수행하겠습니다
하지만 이번 수업이 끝나기 전에 풀어볼 문제가 하나 있습니다
UserDetailsManager을 직접적으로 바로 사용할 수 있을지에 대한 문제입니다
정답은 당연히 "아니다"입니다 왜냐하면 우선 데이터베이스를 생성하고
데이터베이스를 생성한 후
Spring Security 혹은 이 JdbcUserDetailsManager이
예상하는 구조를 기반으로
테이블을 생성해야 하기 때문입니다
그 이후로는 JdbcUserDetailsManagerd에서
공급된 코드만 활용할 수 있는 것입니다
따라서 다음 강의에서는
이번 교육 중에 활용할 수 있는 데이터베이스를
생성해 보겠습니다
감사드리며 다음 강의에서 뵙겠습니다