개발하는 자몽

[Spring Security] @CurrentUser 본문

Java & Kotlin/Spring

[Spring Security] @CurrentUser

jaamong 2025. 7. 12. 12:09

스프링 시큐리티는 `@AuthenticationPrincipal` 애노테이션을 제공한다. 이는 `Authenticaiton.getPrincipal()`를 메서드 인자로 가져오는 데 사용되며, 보통은 `UserDetails` 타입이나 해당 타입의 커스텀 구현체로 가져오게 된다. 

 

`Authentication.getPrincipal()`에는 username, password(AuthenticationManager 구현에 따라 없을 수 있음), role과 같은 사용자 정보가 담겨있다. 

 

간단하게 해당 애노테이션을 그대로 사용해도 되지만, 더 편리하게 사용할 수 있다. 이는 공식문서에서도 안내하고 있다.

 

실제로 구현해 보자. 여기서는 커스텀 애노테이션 이름을 `@CurrentUser`로 설정했다.

import org.springframework.security.core.annotation.AuthenticationPrincipal;

import java.lang.annotation.*;

/**
 * 익명 사용자인 경우에는 null로, 익명 사용자가 아닌 경우에는 실제 Users 객체로
 */
@Target({ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : user")
public @interface CurrentUser {
}

 

`@AuthenticationPrincipal.expression`에 SpEL 표현식을 사용하여 원하는 값을 가져오도록 설정할 수 있다. 위 표현식은 다음을 의미한다. 

  • 현재 객체(`#this`)가 익명 사용자(`anonymousUser`, 인증되지 않음)라면 `null`을 반환
  • 아니라면, `Authentication.getPrincipal()`을 통해 사용자를 나타내는 객체(`UserDetails` 또는 다른 구현체)를 반환

구현을 완료하면 다음과 같이 사용자 객체를 간편하게 애노테이션으로 가져올 수 있다.

...
public class UserController {
	
    ...

    @GetMapping("/info")
    public ResponseEntity<ResponseBody<UserInfo>> getInfo(@CurrentUser Users user) {
        UserInfo userInfo = userInfoService.get(user);
        return ResponseUtil.from(HttpStatus.OK.value(), userInfo);
    }
    ...
}

 

 

참고로 위에서 사용한 `Users` 객체는 직접 정의한 도메인 객체이다.  `UserDetails` 구현체는 아니지만, `UserDetailsService. loadUserByUsername`에서 `UserDetails` 구현체를 생성하여 반환할 때 `Users` 객체를 인자로 넣어주고 있어서 가능하다. 

public class UserDetailsServiceImpl implements UserDetailsService {

    private final UserRepository userRepository;

    @Override
    public UserDetails loadUserByUsername(String email) {
        Users user = userRepository.findByEmail(email)
                .orElseThrow(() -> new UsernameNotFoundException(NOT_FOUND_USER.getMessage()));
        return new CustomUserDetails(user); // 커스텀 UserDetails 클래스 생성자에 직접 구현한 Users 객체를 인자로 넘김
    }

}

 

 

 

Comments