세션 정보 UserDetails에 접근할 수 있는 어노테이션
@AuthenticationPrincipal
은 UserDetails
타입을 가지고 있어서 UserDetails
타입을 구현한 PrincipalDetails
클래스를 받아 User Object
를 얻는다.
@Getter
public class UserAdapter extends CustomUserDetails{
private Member member;
private Map<String, Object> attributes;
public UserAdapter(Member member){
super(member);
this.member = member;
}
public UserAdapter(Member member, Map<String, Object> attributes){
super(member, attributes);
this.member = member;
this.attributes = attributes;
}
}
@Service
@Slf4j
@RequiredArgsConstructor
public class CustomUserDetailsService implements UserDetailsService {
private final MemberRepository memberRepository;
private final HttpSession session;
/** username이 DB에 존재하는지 확인 **/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Member member = memberRepository.findByUsername(username).orElseThrow(() ->
new UsernameNotFoundException("사용자가 존재하지 않습니다."));
/** 시큐리티 세션에 유저 정보 저장**/
return new UserAdapter(member);
}
}
UserDetails
를 상속 받은 UserAdapter
을 통해 커스텀한 Principal를 사용할 수 있다.
인증을 담당하는 loadUserByUsername
에서 Principal(UserDetails)
대신 위에서 만든 UserAdapter
을 반환한다.
loadUserByUsername
메서드의 반환되는 타입을 변경하기 위해 Principal(UserDetails)을 커스텀한 것이다.
(스프링 세션을 사용하면 첫 로그인 시에만 loadUserByUsername
메서드가 호출된다.
JWT로 구현하였다면 매 요청마다 loadUserByUsername
메서드가 호출된다.)