[스프링 시큐리티] Spring Security User 정보 커스텀하기

동민·2023년 4월 19일
0
post-thumbnail

Spring Security를 사용할 때 유저의 정보를 컨트롤러를 통해 Principal 객체를 통해 얻을 수 있다.

@GetMapping("/")
public String main(Principal principal) {
	System.out.println("로그인 유저의 이름 : " + principal.getName());
	return "index";
}

이 방법은 가장 간단하지만, 유저 정보가 필요한 메서드에 전부 작성하는건 너무 귀찮다.

좀 더 개선된 방법으로는 타임리프를 활용하여 authentication.principal 의 정보를 바로 사용하는 것이다.
이 방법은 컨트롤러에서 넘겨주는 복잡한 로직이 전부 제거되기 때문에 컨트롤러 코드가 가벼워지는 장점이 있다.

<svg th:data-jdenticon-value="|${#authentication.principal.username}|"></svg>

Principal 객체를 그대로 사용하면 사용자의 정보가 너무 한정적이다.
화면에서 사용할 수 있는 정보는 username, password 밖에 없다.

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

@Getter
public class MemberContext extends User {

    private final Long id;
    private final String profileIcon;

    public MemberContext(Member member, List<GrantedAuthority> authorityList) {
        super(member.getName(), member.getPassword(), authorityList);
        this.id = member.getId();
        this.profileIcon = member.getProfileIcon();
    }
}

스프링 시큐리티가 제공하는 User 클래스를 상속받는 MemberContext 클래스를 생성하고, 추가로 필요한 id, profileIcon을 추가했다.

@Service
@RequiredArgsConstructor
public class MemberSecurityService implements UserDetailsService {

    private final MemberRepository memberRepository;

    @Override
    @Transactional(readOnly = true)
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Optional<Member> findMember = memberRepository.findByEmail(username);
        if (findMember.isEmpty()) {
            throw new UsernameNotFoundException("사용자를 찾을수 없습니다.");
        }

        Member member = findMember.orElseThrow(() -> new IllegalStateException("해당 회원은 존재하지 않습니다."));

        List<GrantedAuthority> authorities = new ArrayList<>();
        if ("admin".equals(username)) {
            authorities.add(new SimpleGrantedAuthority(MemberRole.ADMIN.getValue()));
        } else {
            authorities.add(new SimpleGrantedAuthority(MemberRole.USER.getValue()));
        }
        return new MemberContext(member, authorities);
    }
}

로그인 시 실행되는 loadUserByUsername() 에서 User 객체가 아닌 MemberContext 객체를 리턴하면 된다. 이때 해당 사용자 객체와 권한을 추가해서 리턴해주면 된다.

이제 view에서 usernamm, password 뿐만 아니라 id, profileIcon 정보도 사용할 수 있다!
Jdenticon을 사용해서 기본 프로필 이미지를 출력하는 view 코드에 사용해봤다.

<svg th:data-jdenticon-value="|member-${#authentication.principal.id}|"></svg>

이미지가 정상적으로 출력되는 것을 확인할 수 있고, MemberContext에 추가한 id 값도 제대로 들어간 걸 확인할 수 있다.

profile
Backend engineer

0개의 댓글