Spring Security - User, UserDetailsService

Ryu·2023년 3월 23일
0

Spring Secuirty 를 구현하다보면, 반드시 UserDetailsService 를 구현해야 한다는 말을 종종 들었다. 왜 반드시 해당 인터페이스를 구현해야 하고, 이 인터페이스가 수행하는 기능은 무엇일까?

UserDetailsService 의 핵심적인 기능은 스프링 시큐리티에서 '인증 관련 정보'를 제공하는 User 클래스를 반환한다는 것이다.
User 클래스는 인증에 필요한 사용자 정보들을 담고 있다.(username, password, authorities)
일단, User 클래스를 구현하는 것부터 알아보자. 본 프로젝트에서는 User 클래스를 상속받는 MemberContext 클래스를 만들어 기능을 확장했다.
MemberContext 를 추가한 이유는 다음과 같다.

  • Member 엔티티에서 가져온 추가 정보를 담아 커스텀한 인증 정보를 만들 수 있다.(email, nickname(작가필명) 등)
  • hasAuthority()라는 커스텀메서드를 통해 특정 권한이 있는지 편리하게 검사할 수 있다.
  • 요약하자면, User 만으로 부족한 인증 관련 정보 객체에 대한 기능을 확장한 것이라고 볼 수 있다.

다음은 실제 구현한 MemberContext 클래스다.

@Getter
public class MemberContext extends User {
    private final Long id;
    private final LocalDateTime createdDate;
    private final LocalDateTime modifiedDate;
    private final String username;
    private final String nickname;
    private final String email;

    public MemberContext(Member member, List<GrantedAuthority> authorities) {
        super(member.getUsername(), member.getPassword(), authorities);
        this.id = member.getId();
        this.createdDate = member.getCreatedDate();
        this.modifiedDate = member.getModifiedDate();
        this.username = member.getUsername();
        this.nickname = member.getNickname();
        this.email = member.getEmail();
    }
    public boolean hasAuthority(String name) {
        return getAuthorities().stream()
                .anyMatch(grantedAuthority -> grantedAuthority.getAuthority().equals(name));
    }

}

왜 UserDetailsService 를 구현해야 하는가 ?

UserDetailsService 는 인증 과정에서 사용할 정보를 가져오는 역할을 수행한다. 즉, User 객체(인증 관련 정보를 담은 객체)를 반환하기 위해 존재하는 것이다. 이 곳에서 User 객체를 완성하고 반환하는 것이 목적이다.

본 프로젝트에서는 UserDetailsService 를 구현한 CustomUserDetailsService 를 만들고, MemberContext(extends User)를 반환하도록 구현했다.

@Service
@RequiredArgsConstructor
public class CustomerUserDetailsService implements UserDetailsService {
    private final MemberRepository memberRepository;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Member member = memberRepository.findByUsername(username).get();
        return new MemberContext(member, member.genAuthorities());
    }
}

반드시 loadUserByUsername()을 오버라이딩한다.

이 때 반드시, loadUserByUsername() 메서드를 오버라이딩 해야한다.
해당 메서드의 기능은 다음과 같다.

  • username 을 입력받아, 해당 사용자 정보를 리포지터리로부터 검색하고 인증 정보 객체를 생성해 반환한다.
  • 쉽게 말해, 사용자 정보를 조회하기 위해 호출해야 하는 메서드이다.
profile
Strengthen the core.

0개의 댓글