[스프링 시큐리티] 현재 인증된 유저 객체 참조


구현 코드 커밋

스프링 시큐리티의 스프링 웹 MVC 지원

@AuthenticationPrincipal

  • 현재 인증된 Principal을 참조할 수 있도록 지원하는 어노테이션
  • Authentication 인터페이스의 구현체(token) 생성자에 전달되는 첫 번째 인자가 Principal
public void login(Account account) {
        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
                account.getNickname(),     // Principal
                account.getPassword(),
                List.of(new SimpleGrantedAuthority("ROLE_USER")));
        SecurityContext context = SecurityContextHolder.getContext();
        context.setAuthentication(token);
    }


  • UserDetailService에서 Return한 시큐리티의 User 객체를 파라미터로 받을 수 있음
  • 시큐리티의 User 객체가 아닌 커스텀한 principal을 사용하고 싶을 때?
@Getter
public class UserAccount extends User {
    private Account account;
    public UserAccount(Account account){
        super(account.getUsername(), account.getPassword(), List.of(new SimpleGrantedAuthority("ROLE_"+ account.getRole())));
        this.account = account;
    }
}

/* 아래처럼 Authentication(token)을 직접 생성할 경우 함께 변경되어야 함 */
/*  */
public void login(Account account) {
        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
                new UserAccount(account)     // Principal
        /* 생략 */
    }
  • 시큐리티의 User를 상속받는 커스텀 클래스를 작성
  • UserDetailService의 구현체에서 loadUserByUsername 메소드를 오버리이딩하여 위에서 작성한 클래스 인스턴스를 반환하도록 하면 커스텀한 Principal(UserAccount) 사용이 가능함
    /* class implements UserDetailSerice */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Account account = accountRepository.findByUsername(username);
        if(account == null){
            return null;
        }
        return new UserAccount(account);
    }
  • Custom Principal 사용
      @GetMapping("/")
      public String home(@AuthenticationPrincipal UserAccount userAccount, Model model){
          ...
      }
    
  • UserAccount로 전달받으면 Account 객체를 사용하기 위해선 매번 getAccount() 메소드를 호출해야 함

만약 UserDetailService에서 반환하는 User 객체가 아닌 프로젝트 도메인에서 사용하는 User(Account) 객체를 바로 사용하고 싶으면?

  • 커스텀 어노테이션
    @Retention(RetentionPolicy.RUNTIME) // 어노테이션 유지 범위
    @Target(ElementType.PARAMETER)      // 어노테이션 적용 위치
    @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : account")
    public @interface CurrentUser {
    }
    
  • 인증을 하지 않은 상태면 Principal에 “anonymoususer”가 담겨있음
  • 따라서 인증 하지 않은 상태면 null로, 인증된 유저면 Account 객체를 반환
    @GetMapping("/")
    public String home(@CurrentAccount Account account, Model model){
        ...
    }





© 2020.02. by blupine