@AuthenticationPrincipal 로그인 정보 받아오기
@AuthenticationPrincipal 을 이용해서 로그인 정보를 받아오는 방법에 대해 알아보겠습니다.
기존 방식
컨트롤러
세션에 저장되어 있는 member의 아이디를 이용해서 조회하여 사용
@GetMapping("/member")
public ResponseEntity<?> findMemberInfo(@RequestParam Long id) {
return ResponseEntity.ok(memberService.findMemberInfo(id));
}
해당 방식으로 사용하면서의 불합리
1. 로그인 사용자의 정보가 필요할 때마다 매번 서버에 요청해서 DB에 접근해서 데이터를 가져온다.
2. 본인이 아닌데 타인의 정보를 확인할 수 있다. (ex. 본인은 1번 아이디인데, 1번 아이디의 token으로 3번 아이디 조회)
Authentication 객체 참조
Authentication 참조 방법
1. 컨트롤러에서 Principal 객체를 주입
- Spring Security가 제공하는 SecurityContextHolder의 Principal 객체가 아닌 자바에 정의되어 있는 Principal 객체를 바인딩 해준다.
- 사용할 수 있는 메소드가 getName() 밖에 없다.
2. 컨트롤러에서 @AuthenticationPrincipal 선언해서 엔티티 객체 받아오기
- Entity에 있는 모든 필드를 참조 가능하다.
3. 컨트롤러에서 @AuthenticationPrincipal 선언해서 엔티티의 어댑터 객체 받아오기 (권장하는 방법)
- 엔티티 객체를 필드로 갖고 있는 어댑터 클래스(DTO)를 생성하여 회원 객체(Member) 상속
- 해당 어댑터 클래스의 엔티티 객체는 DB의 회원 객체의 정보를 담고 있어야한다.
- UserDetailsService의 loadByUsername() 에서 어댑터 클래스를 반환하도록 수정한다.
@AuthenticationPrincial
세션 정보인 UserDetails에 접근할 수 있는 어노테이션이다.
@AuthenticationPrincipal
- UserDetails 타입을 가지고 있기에 UserDetails 타입을 구현한 PrincipalDetails 클래스를 받아 User Object를 얻는다
- userDetails(PrincipalDetails <T>).getUser()
@AuthenticationPrincipal UserAdapter 타입
- 로그인 세션 정보를 어노테이션으로 간편하게 받을 수 있다.
- UserDetailsService에서 Return한 객체의 파라미터를 직접 받아 사용 가능하다.
- name 뿐만 아니라 다양한 정보를 받을 수 있다.
- 중복 코드를 효율적으로 줄일 수 있다.
UserDetails 커스텀
UserDetails를 차후에 있을 Oauth 등을 함께 사용할 수 있게 UserDetails를 Custom 화를 진행
CustomUserDetails
public record CustomUserDetails(CustomUserDto memberDto) implements UserDetails {
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return List.of(new SimpleGrantedAuthority(memberDto.getRoleType()));
}
@Override
public String getPassword() {
return memberDto.getPassword();
}
@Override
public String getUsername() {
return memberDto.getEmail();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
CustomUserDetailsSevice
@Service
@RequiredArgsConstructor
public class CustomUserDetailService implements UserDetailsService {
private final MemberRepository memberRepository;
@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
Member member = memberRepository.findByEmail(email)
.orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND));
return new CustomUserDetails(CustomUserDto.fromEntity(member));
}
}
TokenProvider
public Authentication getAuthentication(String token) {
Claims claims = this.parseClaims(token);
String userId = claims.get("userId").toString();
CustomUserDetails customUserDetails =
(CustomUserDetails) customUserDetailService.loadUserByUsername(userId);
return new UsernamePasswordAuthenticationToken(customUserDetails,
"", customUserDetails.getAuthorities());
}
변경 이후 방식
컨트롤러
@AuthenticationPrincipal 을 이용해서 User 정보를 조회한다.
UserDetails에서 Username으로 설정한 User ID or User Email 리턴한다.
@GetMapping("/member/info")
public ResponseEntity<?> findMemberInfo(@AuthenticationPrincipal CustomUserDetails userDetails) {
return ResponseEntity.ok(memberService.findMemberInfo(userDetails.getUsername()));
}
데이터 조회 방법 변경 이후
1. 한 번 인증된 사용자 정보를 세션에 담아놓고 세션이 유지되는 동안 사용자 객체를 바로 사용
2. 서버에 요청을 보낼 때의 인증 token의 정보를 가지고 본인 정보를 바로 확인
참고
'Spring > 스프링 이론' 카테고리의 다른 글
로그인 유저 어노테이션 기반으로 정보 가져오기(@AuthenticationPrincipal 커스텀) (0) | 2023.12.24 |
---|---|
WebSecurityConfigurerAdapter deprecated 대체하는 방법 (0) | 2023.12.08 |
스프링부트를 이용한 유효성 검사(feat. Validation) (0) | 2023.11.22 |
댓글