본문 바로가기

IT

Spring Security User(UserDetail) 커스텀

728x90

spring security를 사용할 때 사용자의 정보를 컨트롤러를 통해 Principal 객체를 통해 얻을 수 있었다. 

Principal 객체

하지만 이 방법을 사용하여 사용자의 정보가 필요한 페이지마다 이 작업을 모두 추가해주기는 번거롭다. 

 

이를 고려하여 두번째 방법으로는 컨트롤러에서 넘겨주는 복잡한 로직을 제거하기 위해 타임리프를 활용하여 authentication.principal의 정보를 바로 사용하는 것이다. 

authentication.principal.username

하지만 이 방법으로는 사용자의 정보는 한정적이다. 확인해보면  사용할만한 정보가 username과 password 뿐이다. 

authentication.principal
authentication.principal 출력

 

따라서 spring security가 회원의 정보를 세션에 담을 때 더 많은 정보를 담고 있으면 우리는 추가적으로 이러한 한정적인 정보를 벗어나서 사용할 수 있다. 스프링 시큐리티가 로그인시에 넣어주는 정보를 강화해보자.

생각 외로 아주 간단하다.

@Getter
public class MemberContext extends User {
    private final Long id;
    private final String profileImgUrl;

    public MemberContext(Member member, List<GrantedAuthority> authorities) {
        super(member.getUsername(), member.getPassword(), authorities);
        this.id = member.getId();
        this.profileImgUrl = member.getProfileImgUrl();
    }

User라는 스프링 시큐리티가 지원하는 객체를 상속받는 MemberContent라는 클래스를 생성하였고 기존 User가 가지는 username과 password 이외에 id와 profileImgUrl을 추가하였다. 

@Service
@RequiredArgsConstructor
public class MemberSecurityService implements UserDetailsService {
    private final MemberRepository memberRepository;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Member member = memberRepository.findByUsername(username).get();

        List<GrantedAuthority> authorities = new ArrayList<>();
        authorities.add(new SimpleGrantedAuthority("member"));

        return new MemberContext(member, authorities);
    }
}

UserDetailService를 상속받는 MemberSecurityService를 구현하였고 loadUserByUsername을 오버라이드하여 구현하였다. 그리고 위에서 구현한 MemberContext를 기존 사용자 객체와 권한을 추가하여 리턴하면 끝이다. MemberContext는 이 매개변수를 통해 기존 username, password, authorities는 super()를 통해 생성되고 추가한 id, profileImgUrl을 사용할 수 있게 된다. 

authentication.principal.profileImgUrl

이제 우리는 username과 password뿐 만 아닌 여러 정보를 authentication.principal를 통해서 view에서 사용할 수 있다.