💙 들어가며
JDBC를 활용한 UserDetails를 먼저 구현해보고,
이를 확장한 커스텀한 UserDetails을 만들어보자.
✏️ 학습내용 정리
#사용자의 정보를 controller에서 꺼내오기: SecurityContextHolder
전역객체이기 때문에
어느 페이지에서나
Principal, Credentials, Authorities를
꺼내쓸 수 있다.
principal로 getName() 해보자
⭕ 출력결과
해당 페이지가 요청될 때마다
로그인한 이름이 출력되는 것을 확인할 수 있다.

#ROLE이 여러개인 경우: 다대다 테이블
💡 jdbc UserDetailsService 구현 시 주의:
사용자 입력을 받는 부분은 반드시 물음표(? )로 처리한다.
member 테이블, role 테이블이 따로 있어서
둘을 join한 member_role 테이블을 만든뒤
select로 뽑아온다.
하나의 아이디가 여러개의 role을 가질 수 있는데,
문제없다!
스프링에서 알아서 배열형태로 담는다.
sql에서 join한 값을 입력한다.
이때 반드시 사용자입력 부분은
물음표(? )로 처리한다.
Spring Security는
username이 PK라고 인식해서
글을 등록할 때 username만 있으면 된다고 생각한다.
하지만 진짜 PK는 id로 인식이 되어야 한다.
1. 그러면 쓸 때마다 id를 매번 찾아오거나
2. 세션에 담아놓는 방법이 있겠다.
하지만 이렇게 되면,
username은 스프링이 가진 userdetails에서 가져오고
그 외 기타 정보는 세션에 담아서 가져오니
하나의 유저 정보를 따로따로 가져오는 느낌이 든다.
(확장이 필요한 정보)
확장을 하게 되면 결국 확장된 개체와
userdetails 객체를 따로 만들어야 한다.
그렇다면 Spring Security의
userdetails를 확장할 수는 없을까?
3. userdetails를 자체를 확장해서 (커스텀)
이 자체를 세션에 담아서 사용해보자.
▶ 가장 보편적으로 사용되는 방법이다.
#커스텀 UserDetailsService
이제까지는 스프링에서 제공하는
UserDetaisService의 틀을 그대로 사용했지만
커스텀해서 사용하려고 한다.
먼저,
UserDetails 인터페이스를 상속받는 클래스를 하나 만든다.
필수로 제공하는 것들은 다 기록하되
더 필요한 정보가 있으면 추가한다.
UserDetails를 위한 데이터구조를 정의했다면
스프링이 인식할 수 있게
UserDetailsService를 따로 만들어주어야 한다.
일단 먼저 데이터구조부터 짜보자.
인터페이스를 상속받으면
getter는 들어가 있지만 setter는 없다.
우리가 값을 대입할 수 있게 setter를 준비해주고
필요한 변수들도 입력해준다.
UserDetailsService도 커스텀해보자.
UserDetailsService 인터페이스를 상속받은 클래스를 만든다.
반드시 객체화 되어 있어야 스프링이 인식하기 때문에
클래스로 만들었다면
@Component 혹은 @Service를 붙여준다.
(혹은 RlandSecurityConfig에서
메소드로 정의하고 @Bean으로 만들어도 된다.)
#확장된 속성 얻기
상위의 값인 Authentication을 불러온다.
임포트할 때 주의
Authentication을 통해 반환하는 principal은
userdetails 객체이다.
따라서 이름만 가지고 있는
그냥 principal이랑 다르게
확장된 정보를 다 가지고 있다.
💡 주의: 형변환 해주기! 안하면 그냥 Object임!
뷰에서 직접받을 수 있기 때문에
컨트롤러에서 인증정보를
뷰에게 모델로 반환하지 않는다.
뷰에서 스스로 꺼내 쓸 수 있는 것은
컨트롤러에서 꺼내올 필요가 없기 때문이다.
다음 시간에는 타임리프를 통해서
인증했던 데이터를 꺼내볼 예정!
💙 마치며
1.
일반 principal은 username만 가지고 있지만
Authentication을 통해 반환하는
principal 객체는
userDetails 객체 그 자체라는 점을 잘 기억하자.
(확장된 정보를 다 가지고 있다.)
2.
커스텀 userDetails를 만들었다면
커스텀 userDetialsService도 만들어줘야 한다.