티스토리 뷰

Java

@AuthenticationPrincipal

kingsubin 2021. 3. 1. 19:00

Principal

로그인한 사용자의 정보를 파라미터로 받고 싶을때 Principal 아래와 같이 객체로 받아서 사용할 수 있다.

Principal 객체는 java.security 패키지에 속해있는 인터페이스이며
getName() 을 통하여 name 정보를 참조할 수 있다.

@GetMapping()
public String index (Model model, Principal principal) {
    if (principal == null) {
        model.addAtrribute("msg", "Hello");
    } else {
        model.addAtrribute("msg", "Hello" + principal.getName());
    }

    return "index";
}

 


@AuthenticationPrincipal

다른 방법을 찾아보니 @AuthenticationPrincipal 이 존재한다.
이 애노테이션은 파라미터와 애노테이션 타입에 적용가능하며 런타임시 작동한다.
안에 설명을 보면 Authentication.getPrincipal() 메소드 인자로 사용한다고 적혀있다.

@Target({ ElementType.PARAMETER, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)

파라미터와 애노테이션 타입에 적용가능하며 런타임시 작동한다.

@GetMapping()
public String index (@AuthenticationPrincipal User user) {
    if (principal == null) {
        model.addAtrribute("msg", "Hello");
    } else {
        model.addAtrribute("msg", "Hello" + user.getUsername());
    }

    return "index";
}
Then the user can specify an annotation that looks like:
@AuthenticationPrincipal(expression = "customUser")

애노테이션 사용시 UserDetailsService 에서 Return 한 객체를 파라미터로 직접 받아올 수 있다.

 


현재 Account 에 대한 애노테이션 만들기

다른 사람이 이렇게 사용한걸 보고 뭔지 모르겠어서 찾아보았다.

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : account")
public @interface CurrentAccount {
}
@Getter
public class UserAccount extends User {

    private Account account;

    public UserAccount(Account account) {
        super(account.getNickname(), account.getPassword(), List.of(new SimpleGrantedAuthority("ROLE_LEVEL_1")));
        this.account = account;
    }
}

 

  • 현재 참조중인 객체가 AnnonymousAuthenticationFilter 에 의해 생성된 Authentication 인 경우 null 반환, 아니면 User 를 상속받은 UserAccount 를 반환한다.
  • Account 객체에서 UserDetails를 구현하여 사용하여도 되지만 직접 리턴하는 방법은 도메인 클래스에 영향을 미치니 추천하지 않고 위와 같이 UserAccount 객체를 따로 만듬.

 

@GetMapping()
public String index (@CurrentAccount Account account) {
   if (account == null) {
        model.addAtrribute("msg", "Hello");
    } else {
        model.addAtrribute("msg", "Hello" + account.getUsername());
    }
    return "index";
}

 

 


정리

- 기존에는 java.security 의 Principal 을 사용하여 현재 유저를 가져왔는데 참조할 수 있는 정보는 name 뿐이다.

- 근데 @AuthenticationPrincipal 사용시 UserDetailsService 에서 리턴한 객체를 사용할 수 있다.

- 그래서 @AuthenticationPrincipal 을 사용.

- 근데 매번 파라미터에 @AuthenticationPrincipal 사용하는 것도 문제고 위에서 만든 UserAccount 객체가 Account 객체를 감싸고 있으니 직접 접근하려면 매번 .getAccount() 를 통해야 하다보니 중복된다.

- 그래서 Account 객체를 직접 사용하기 위해서 SpEL 을 지원하는 것을 이용하여 @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : account") Account 객체를 직접 가져올 수 있다.

- 근데 매번 SpEL 을 적으면 코드도 길고 매번 컨트롤러에 적어야한다.

- 이를 해결하기 위해 @CurrentAccount 라는 커스텀 애노테이션을 만들었다.

 

'Java' 카테고리의 다른 글

ModelMapper  (0) 2021.03.04
@InitBinder  (0) 2021.02.26
java validation  (0) 2021.02.26
13. I/O  (0) 2021.02.24
12. 애노테이션  (0) 2021.02.06