개요
로그인한 사용자의 정보를 매개변수로 전달받을 방법을 고민하던 중 편리하게 사용할 수 있는 어노테이션이 있어 간단히 정리하고자 합니다.
이 내용은 대부분 엔꾸꾸님이 정리하신 내용과 동일하므로 엔꾸꾸님 블로그를 참고하시는 것을 추천합니다.
1. @AuthenticationPrincipal 어노테이션 없이 로그인한 사용자의 정보를 불러오는 방법
해당 어노테이션을 사용하기 전에는 Principal 객체를 통해 로그인한 사용자를 받아올 수 있지만 이는 SecurityContextHolder 내 Principal(SecurityContextHolder.getContext().getAuthentication().getPrincipal())과는 달리 Java 표준 Principal 객체이므로 name 정보밖에 불러오지 못하는 한계가 있습니다.
@AuthenticationPrincipal 어노테이션을 사용할 경우 UserDetailsService에서 반환한 객체를 매개변수로 직접 받아 사용할 수 있지만 현재 제가 원하는 방법은 로그인한 사용자의 정보를 참조하고 싶을 때 domain 패키지 내 사용자를 나타내는 Account 객체를 직접 사용하고 싶으로 Adapter 클래스를 사용해야 합니다.
UserDetailsService
2. Adapter 클래스 사용
앞서 언급했던 것처럼 UserDetailsService에서 반환하는 타입을 변경할 경우 @AuthenticationPrincipal 어노테이션으로 받아올 수 있는 객체가 변경됩니다.
이 때 사용할 수 있는 방법은 크게 두 가지인데 이는 아래와 같습니다.
- Account 객체를 직접 반환
- Account 객체를 감싸는 Adapter 클래스를 구현
두 가지 방법 중 후자를 택한 이유는 도메인 객체는 특정 기술에 종속되지 않도록 개발하는 것이 추천되기 때문입니다.
Adapter 클래스를 사용하면 아래와 같이 구현할 수 있습니다.
해당 Adapter가 org.springframework.security.core.userdetails.User를 상속받는 이유는 UserDetailsServicce가 반환하는 객체는 UserDetails 타입이 여야 하기 때문입니다.
이제 Controller에서 @AuthenticationPrincipal 어노테이션과 함께 매개변수로 UserAccount 객체를 받으면 현재 로그인한 객체를 받아올 수 있습니다.
하지만 여기서 문제점?이라고 한다면 로그인한 사용자의 정보를 받아오고 싶을 때마다 UserAccount.getAccount()와 같이 getter를 통해 접근해야 한다는 점입니다.
이를 해결하기 위해서는 스프링 표현 언어(SpEL)를 사용하면 됩니다.
3. SpEL 적용
현재 참조 중인 객체가 AnonymousAuthenticationFilter에 의해 생성된 Authentication인 경우 즉, 현재 유저가 로그인되어 있지 않다면 null을 반환하고, 로그인이 되었다면 UserAccount 객체로 간주하기 때문에 UserAccount 객체가 감싸고 있는 Account 객체를 반환합니다. (만약, domain으로 생성된 객체 클래스명이 Account가 아니라 예를 들어 LoginUser라면 SpEL에 account가 아니라 loginUser를 반환하도록 해야 합니다.)
이렇게 SpEL까지 적용하면 getter를 사용할 것 없이 깔끔하게 로그인한 사용자의 domain 객체에 바로 접근할 수 있습니다.
하지만, 코드 블록에서도 볼 수 있다시피 파라미터가 상당히 길어져서 가독성이 그다지 좋지 았으며 재사용성이 떨어집니다.
위 문제를 해결하기 위해서는 커스텀 어노테이션을 생성하면 됩니다.
4. 커스텀 어노테이션 생성
커스텀 어노테이션은 아래와 같이 생성하면 됩니다.
RetentionPolicy를 Runtime까지 남아있도록 설정하고 매개변수에 사용할 것이므로 @Target을 파라미터로 설정해줘야 합니다.
이렇게 커스텀 어노테이션까지 설정하면 아래와 같이 깔끔한 컨트롤러를 구현할 수 있습니다.
참고
인프런 강의 - 스프링과 JPA 기반 웹 애플리케이션 개발 (백기선 강사님)
'Spring > Spring Security' 카테고리의 다른 글
[Spring Security] 필터 체인과 커스텀 필터 (0) | 2024.10.08 |
---|---|
[Spring Security] 액세스 제한과 권한 (0) | 2024.10.07 |
[Spring Security] 아키텍처 간단 정리 (0) | 2024.09.13 |
[Spring Security] OAuth 2.0 개요 (0) | 2023.12.21 |
[Spring Security] Remember-me를 통해 로그인 유지하기 (0) | 2022.03.27 |