이번 강의에서는
우리가 새로 만든 테이블에서의
권한 정보를 읽기 위한
코드 변경을 진행해 봅시다
저는 우선 비슷하게 새로운 테이블 권한을 위해
모델 패키지 내에
새로운 엔터티 클래스를 만들어 보겠습니다
여기서 클래스 이름은 Authority로 지정할 수 있습니다
먼저 여기서는
몇 가지의 주석을 언급하겠습니다
제일 첫 번째는 @Entity 그 다음으로 @Table 입니다
여기서 주석 @Table 를 사용하는 이유는
저의 테이블 이름이 클래스 이름과 다르기 때문입니다
제 테이블의 이름은 Authority가 아닌 authorities 입니다
Authority의 복수형이죠
그래서 저는 테이블 주석을 사용할 수 밖에 없습니다
이것과 상관없이 데이터베이스 내의
실제 테이블 이름은 무엇일까요?
이는 Spring Data JPA가
나의 데이터베이스에서
SQL 쿼리를 실행하려고 할 때마다
이러한 테이블 이름을 활용하기 위함입니다
자 이제 이 Java 클래스 내에
몇 줄의 코드를 붙여 넣겠습니다
한 줄씩 살펴봅시다
여기서 저는 첫 번쨰로
권한 테이블 내의
주요 키 밸류를 나타내기 위해
필드 ID를 생성했습니다
그래서 우리의 고객 테이블에 사용한 것과 같이
이 세 가지의 주석을 사용하고 있습니다
그 ID 다음에는 이름 필드가 있고
데이터베이스 열의 이름이
이미 같은 이름이기에
따로 @Column에 대해 언급할 필요가 없습니다
다음으로 제 고객에 대한
객체 참조가 있습니다
이 고객 필드를 활용하여
Spring Data JPA에게
이 권한이 부모 테이블인
고객과의 연결이 있다고 전달하려고 합니다
그리고 이 고객과 권한 간의 연결을 수립하려면
권한 내부에서 @ManyToOne과 같은 주석을 사용해야 합니다
어떤 열이 이 두 테이블을
결합하는 역할을 하는 것일까요?
그렇다면 이 두 테이블을 결합하는 열은
"customer_id"입니다
이 @ManyToOne 주석을 사용하여
Spring Data JPA에게 여러 권한이
단일 고객에 매핑될 수 있음을
알리고 있습니다
당연히 우리는 ManyToMany를 사용할 수도 있습니다
하나의 권한이 여러 명의
고객에게 배정될 수도 있습니다
그러나 지금은 Spring Data JPA에 대해
복잡한 주제로 들어가고 싶지는 않습니다
지금 이 구성이 충분할 것으로 생각됩니다.
Spring Data JPA 및
이러한 주석에 관한
더 많은 질문이 있다면
제 Spring 강좌를 참조해 주시길 바랍니다
이어서 저는 이 세 가지의 필드를 위해
getters and setter 메소드를 생성했습니다
그렇다면 권한 엔터티 관점에서는 이로써 문제가 해결되었습니다
다시 고객 엔터티 클래스로 돌아가서
우리는 또 다시 권한 테이블과 관련하여
링크를 만들어야 합니다
저는 이 엔터티 내에 비슷하게
새로운 필드를 만들 겁니다
필드의 이름은 authorities입니다
여기서 저는 이 필드를
권한 세트라고 정의내렸습니다
이유는 한 명의 고객이
여러 가지 권한을 가질 수 있기 때문입니다
이것이 우리가 어떤 컬렉션을 사용하든
편안한 대로
권한 집합 또는 권한 목록을 사용하는 이유입니다
이 필드 권한에 덧붙여
@OneToMany라는 주석을 붙여야 합니다
우리는 이 주석을
Spring Data JPA에게 단일 고객 레코드가
권한 테이블 내의 여러 레코드와 결합되어
이를 전달하려고 할 때 사용합니다
이게 바로 우리가
@OneToMany 주석을 사용하는 이유입니다
그리고 mappedBy에서 우리는
권한 엔터티 내에서 가지고 있는
같은 필드 이름을 사용하는지 확인해야 합니다
필드 이름은 customer 입니다
그래서 여기서 mappedBy에 대해
동일한 필드 이름을 언급해야 하며
그 후에 FetchType을 EAGER로 설정하고 있습니다
FetchType EAGER에서
Spring Data JPA에게 전달하려는 내용은
Spring Data JPA가
고객 세부 정보를 로드하려고 할 때
권한 세부 정보도 즉시 로드하도록 하여
비즈니스 로직 내에서 활용할 수 있도록 하는 것입니다
이 필드를 정의하였다면
이제는 이러한 필드 권한들을 위한
getter와 setter를 정의해야 합니다
클래스의 끝으로 가서
setCreateDate 바로 뒤에
권한을 위한 getter 메소드와 setter 메소드를 만듭니다
그리고 여기에 @JsonIgnore 이라는 주석이 있습니다
이 주석의 목적이 무엇인지에 대해
질문 하실 수도 있을 것 같습니다
어느 필드에서든 다음과 같은 주석이
언급되면
이 필드는 UI 애플리케이션으로 보내지는
JSON response에 보내지지 않는다는 뜻입니다
왜냐하면 제 시나리오에서는
이 민감한 정보를 UI 애플리케이션에
공유하고 싶지 않기 때문입니다
이 권한 정보를 오직
백엔드 애플리케이션에서만 사용하고자 합니다
따라서 UI 애플리케이션에 작동하는
JSON 커뮤니케이션 내에
필드가 참여하지 않기를 원하는
다음과 같은 시나리오에서는 언제든
@JsonIgnore 주석을 사용하면 됩니다
반면에 비밀번호에서는 @JsonIgnore를 사용하지 않았습니다
그 이유는 우리는 UI 애플리케이션에서
백엔드로 비밀번호의 세부정보가 필요하기 때문입니다
예를 들어 유저가 로그인 하거나
회원가입하려고 할 때
JSON request에서는 비밀번호의 세부정보가 필요합니다
따라서 이때는 @JsonIgnore을 사용하지 않습니다
이럴 때에는 @JsonProperty 주석을 사용해야 합니다
그리고 그 액세스 값을 WRITE_ONLY로 정의할 수 있습니다
WRITE_ONLY로 설정하면서 전하려는 것은
UI에서 백엔드로 오는 요청 내에서
이 필드를 항상 원하지만
데이터베이스에서 로드한 암호 세부 정보를
UI 애플리케이션으로
다시 전송하고 싶지 않다는 것입니다
보안의 이유로 다시 이러한 상황이
발생하는 것입니다
우리는 데이터베이스에서 로드한 해시
또는 비밀번호 값을 네트워크 및
UI 애플리케이션으로 전송하고 싶지 않습니다
악용될 경우가 있을 수 있기 때문입니다
여기서 우리는
새로 만든 테이블을 기반으로
웹 애플리케이션 내에
모든 Spring Data JPA 관련 엔터티 변환을 가지고 있습니다
다음 단계로 우리가 해야 하는 것은
고객 세부 정보를 로드하려고 할 때마다
권한 정보들이
AuthenticationProvider 안에
로드되기 때문에
이제부터는 고객 테이블로부터
권한과 역할에 대한 정보를 읽을 것입니다
그 대신 이러한 권한들을
getAuthorities 메소드를 활용할 것입니다
AuthenticationProvider 내에
몇 가지 수정을 해보겠습니다
제일 먼저 할 수정은
이 AuthenticationProvider 내에
helper 메소드를 생성할 것입니다
getGrantedAuthorities의 목적이 우리가
백엔드 데이터베이스에서 발행했던
권한의 집합을 전달할 수 있냐였다면
helper 메소드는 권한 엔터티 클래스로부터
실제 권한의 열 이름을 읽는 것입니다
그리고 모든 엔드 유저의 권한을 위해
우리의 데이터베이스 내의
권한의 이름을 전달하여
SimpleGrantedAuthority 객체를 생성하는 것입니다
마지막으로 우리는 UsernamePasswordAuthentication의 생성자에게
똑같이 전달하기 위하여
GrantedAuthority 리스트로 돌아올 것입니다
여기서 이 권한 리스트를
활용하는 것 대신
우리는 직접적으로 getGrantedAuthorities 메소드를 불러오면 됩니다
그리고 이 메소드에 getAuthorities 메소드의 도움을 받아
우리가 데이터 베이스에서 로드한
권한들을 전달하면 됩니다
따라서 다음 두 줄은 더 이상 필요하지 않습니다
이 줄들은 삭제합니다
자 이제 우리는 완벽하게 데이터베이스로부터
권한 세부정보를 로딩하고 있고
UsernamePasswordAuthenticationToken의
생성자에게 똑같이
전달하고 있습니다
이 강의에서 수행한 모든 변경 사항을
빠르게 확인하려면
여기에 중단점을 설정한 후
웹 애플리케이션에 로그인을 시도할 수 있습니다
먼저 빌드를 해봅시다
빌드가 완료되고 나면
Spring Boot Main 클래스를 엽니다
그러고 디버그 모드에서
해당 애플리케이션을 실행합니다
이로써 제 웹 애플리케이션은 포트 8080에서 실행됩니다
이제 브라우저로 가서 로그인을 시도하고
우리가 설정한 코드를 기반으로
권한들이 로딩되는지 확인하면 됩니다
여기서 저의 UI 애플리케이션에 로그인을 시도해보겠습니다
제 UI 애플리케이션도 시작되었습니다
포트 4200에 접근합니다
저의 UI 애플리케이션이 열립니다
여기서 로그인을 클릭합니다
그리고 이메일 happy@example.com을 입력합니다
비밀번호는 12345
여기서 로그인을 클릭하면
제 AuthenticationProvider 내에 실행이 멈춥니다
그럼 한 줄씩 디버깅을 시도해 봅니다
그래서 이제 내가 가지고 있는
이 고객 객체 위에 호버하면
권한 아래에 "VIEWCARDS"와 같이 네 개의 레코드가 있는 것을 볼 수 있습니다
매우 유사하게 다른 권한도
데이터베이스에서
완벽하게 로드되었습니다
또한 권한 엔터티와 고객 엔터티 내에서 작업했던
엔터티 수정을 기반으로
Spring Data JPA에 의해 작동하는
SQL 쿼리도 확인할 수 있습니다
여기서 보듯이
먼저 고객 세부 정보를 가져오려고 시도했고
그 후에는 해당 고객 ID를
기반으로 권한 세부 정보를
가져오려고 시도했습니다
따라서 우리의 모든 권한은
완전하게 로드되었습니다
중단점을 해제하고
현재 우리의 인증이
성공했음을 확인할 수 있습니다
우리가 대쉬보드를 볼 수 있는 이유입니다
여기 계정을 클릭해볼 수도 있습니다
모든 운영이 정상적으로 작동합니다
이로써 우리는 엔드 유저의 모든 권한을
성공적으로 로드했으며
권한을 로드하는 것 외에도
인증 객체를 생성하려고 할 때
Spring Security 프레임워크에
권한 세부 정보를 전달하고 있습니다
이것이 바로 우리가 AuthenticationProvider 내에서
UsernamePasswordAuthenticationToken 객체를
만들려고 할 때마다
수행하는 작업입니다
다음 강의부터는
권한들을 활용하고
웹 애플리케이션 내에
몇 가지의 인가를 강제해보도록 하겠습니다
감사드리며 다음 강의에서 뵙겠습니다
수고하셨습니다