barded
[어디가게] @AuthenticationPrincipal 및 Custom Annotation을 사용하여 로그인한 사용자 정보 가져오기 본문
프로젝트/어디가게
[어디가게] @AuthenticationPrincipal 및 Custom Annotation을 사용하여 로그인한 사용자 정보 가져오기
barded 2023. 12. 12. 17:25로그인한 사용자의 정보를 파라미터로 가져오고 싶을때 `Java`의 표준 `Principal` 객체를 받아와 사용할 수 있지만 `Principal` 객체는 `name` 정보만 참조할 수 있다. 이때 `@AuthenticationPrincipal` 애노테이션을 사용하면 `UserDetailService`에서 return하는 객체를 파라미터로 직접 받아 사용할 수 잇다.
//ava 표준 Principal 객체를 받아서 사용
@GetMapping("/")
public String index(Model model, Principal principal) {
if (principal == null) {
model.addAttribute("message", "Spring security");
} else {
model.addAttribute("message", "Hello, " + principal.getName());
}
return "hello";
}
//@AuthenticationPrincipal 어노테이션을 사용
@GetMapping("/")
public String index(Model model, @AuthenticationPrincipal User user) {
if (user == null) {
model.addAttribute("message", "Spring security");
} else {
model.addAttribute("message", "Hello, " + user.getName());
}
return "hello";
}
그렇다면 현재 로그인한 사용자의 정보를 참조하고 싶을때 도메인을 나타내는 객체(여기서는 `Account`)를 직접 사용하고 싶은경우에는??
Adapter 클래스를 사용하기.
`UserDetailService`에서 반환값을 변경하면 `Controller`에서 `@AuthenticationPrincipal`로 받아올 수 있는 객체가 변경된다.
이때 1. `Account` 객체 직접 반환 하는 방식과, 2. `Account`를 객체를 감싸는 `Adapter` 클래스를 사용할 수 있다.
도메인 객체는 특정 기술에 종속되지 않도록 개발하는 것이 좋으므로 `Adapter클래스`를 사용하자
AccountAdapter.java
@Getter
public class AccountAdapter extends User {
private Account account;
public AccountAdapter(Account account) {
super(account.getUserId(), account.getPassword(), authorities(account.getRoles()));
this.account = account;
}
private static Collection<? extends GrantedAuthority> authorities(Set<AccountRole> roles) {
return roles.stream()
.map(r -> new SimpleGrantedAuthority(r.getRole().authority()))
.collect(Collectors.toSet());
}
}
- User 클래스를 상속받는다.
- AccountAdapter의 멤버는 오로지 Account 객체만 존재한다.
- 생성자 내부에서 User 클래스의 생성자를 호출하여 username, password, role을 설정한다.
CustomUserDetailsService.java
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Account account = accountRepository.findByUserId(username);
if (account == null) {
throw new UsernameNotFoundException("user not found");
}
return new AccountAdapter(account);
}
AccountAdapter사용하기
@GetMapping("/")
public String index(Model model, @AuthenticationPrincipal AccountAdapter accountAdapter) {
if (accountAdapter == null) {
model.addAttribute("message", "Spring security");
} else {
model.addAttribute("message", "Hello, " + accountAdapter.getAccount().getUserId());
}
return "index";
}
@AuthenticationPrincipal은 SpEL을 지원하므로 Account 객체를 직접 가져올 수 있다.
하지만 너무 기므로 커스텀 애노테이션으로 해결하자!
CurrentUser.java
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : account")
public @interface CurrentUser {
}
@GetMapping("/")
public String index(Model model, @CurrentUser Account account) {
if (account == null) {
model.addAttribute("message", "Spring security");
} else {
model.addAttribute("message", "Hello, " + account.getUserId());
}
return "index";
}
- @AuthenticationPrincipal을 사용하여 UserDetailsService에서 리턴한 객체를 컨트롤러의 파라미터로 직접 참조할 수 있다.
- 만약 도메인의 User를 표현하는 클래스(Account)를 직접 참조하고 싶다면 Adapter 클래스를 사용하자
'프로젝트 > 어디가게' 카테고리의 다른 글
[어디가게] 컨트롤러에서 여러 서비스를 불러야 하는경우 (0) | 2024.03.18 |
---|---|
[어디가게]Spring Security단에서 OPEN-SESSION-IN-VIEW 영속성 컨텍스트 (0) | 2024.03.18 |
[어디가게]UserDetails에 저장하는 정보 및 유니크한 프라이머리키와 유니크한 컬럼 간의 쿼리 속도 (0) | 2024.03.18 |
[어디가게] Spring Security단에서 발생하는 Exception의 처리 불가능 (0) | 2024.03.18 |
[어디가게] 사용자의 역할을 구분하면서 생기는 문제에 대한 테이블 설계 방안 (0) | 2023.11.30 |