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 값도 제대로 들어간 걸 확인할 수 있다.