1. 개요
@AuthenticationPrincipal 어노테이션은 Spring Security를 사용할 때 현재 인증된 사용자의 정보를 가져오는 데 사용된다.
이를 활용하여 Controller 및 ServiceImpl 클래스에서 현재 인증된 사용자의 정보를 가져오는 부분을 변경하고자 함.
먼저, Controller에 해당 어노테이션을 추가하여 UserDetails를 가져온 후, ServiceImpl에 필요한 사용자 정보를 파라미터로 전달한다.
2-1. RecordController 변경 전
// class,class 위 어노테이션 생략
private final RecordService recordService;
@PostMapping
public ResponseEntity<String> recordTime(@RequestBody RecordDto recordDto) {
try {
recordService.recordTime(recordDto.getRecordedTime());
return ResponseEntity.ok("시간이 성공적으로 기록되었습니다.");
} catch (RecordTimeException e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("시간을 기록하는 중에 오류가 발생했습니다.");
}
}
2-2. RecordController 변경 후
// Class, Class 위 어노테이션 생략
@PostMapping
public ResponseEntity<String> recordTime(@RequestBody RecordDto recordDto,
@AuthenticationPrincipal UserDetails userDetails) {
try {
recordService.recordTime(recordDto.getRecordedTime(), userDetails);
return ResponseEntity.ok("시간이 성공적으로 기록되었습니다.");
} catch (RecordTimeException e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("시간을 기록하는 중에 오류가 발생했습니다.");
}
}
recordTime 메서드의 파라미터로 '@AuthenticationPrincipal UserDetails userDetails' 가 들어간 것을 볼 수 있다.
2-3.RecordService 변경 전
public interface RecordService {
void recordTime(String recordedTime);
}
2-4.RecordService 변경 후
public interface RecordService {
void recordTime(String recordedTime, UserDetails userDetails);
}
recordTime 메서드에서 userDetails 를 RecordTimeController 를 통해 불러오기 위한 변경이다.
2-5.RecordServiceImpl 변경 전
private final AccumulatedTimeRepository accumulatedTimeRepository;
private final UserRepository userRepository;
@Override
public void recordTime(String recordedTime) {
try {
// 현재 로그인된 사용자의 정보를 가져오는 부분 (이 부분은 Spring Security 을 통해 구현)
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || !authentication.isAuthenticated()) {
throw new RuntimeException("사용자가 로그인되지 않았습니다.");
}
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
String username = userDetails.getUsername(); // 혹은 이메일, 당신의 시스템에서 사용하는 것에 따라 달라집니다.
User currentUser = userRepository.findByUsername(username).orElseThrow(() -> new RuntimeException("사용자를 찾을 수 없습니다."));
// 해당 사용자의 누적 시간을 조회하거나 새로 생성합니다.
AccumulatedTime accumulatedTime = accumulatedTimeRepository.findByUser(currentUser)
.orElseGet(() -> {
AccumulatedTime newAccumulatedTime = new AccumulatedTime();
newAccumulatedTime.setUser(currentUser);
currentUser.setAccumulatedTime(newAccumulatedTime);
return newAccumulatedTime;
});
RecordServiceImpl 에서 자체적으로 Authentication 의 SecurityContextHolder 를 직접 호출하는 것을 볼 수 있다.
2-5.RecordServiceImpl 변경 후
@Override
public void recordTime(String recordedTime, UserDetails userDetails) {
try {
String username = userDetails.getUsername();
User currentUser = userRepository.findByUsername(username)
.orElseThrow(() -> new RuntimeException("사용자를 찾을 수 없습니다."));
// 기존 코드 (변경 없음)
AccumulatedTime accumulatedTime = accumulatedTimeRepository.findByUser(currentUser)
.orElseGet(() -> {
AccumulatedTime newAccumulatedTime = new AccumulatedTime();
newAccumulatedTime.setUser(currentUser);
currentUser.setAccumulatedTime(newAccumulatedTime);
return newAccumulatedTime;
});
long newAccumulatedMinutes = accumulatedTime.getAccumulatedMinutes() +
parseRecordedTime(recordedTime);
accumulatedTime.setAccumulatedMinutes(newAccumulatedMinutes);
accumulatedTimeRepository.save(accumulatedTime);
} catch (Exception e) {
log.error("Error recording time", e);
throw new RecordTimeException("시간을 기록하는 중에 오류가 발생했습니다.");
}
}
@AuthenticationPrincipal 어노테이션을 활용하여 UserDetails 객체를 가져와 Service로 전달한 모습이다.
이로써 ServiceImpl에서는 SecurityContextHolder를 직접 호출하지 않고도 현재 인증된 사용자의 정보를 얻을 수 있다.
3. 요약
@AuthenticationPrincipal 을 쓰지 않으면 RecordServiceImpl 변경 전 처럼 SecurityContextHolder 에서 DB 조회를 할때마다 해야하는데, @AuthenticationPrincipal 를 쓰면 DB 조회 직접적으로 안해도 되어서 서버 리소스 사용하는게 줄어들게 된다.
'Spring' 카테고리의 다른 글
Spring 기본 dependency 설정 (0) | 2023.10.12 |
---|---|
Spring ) SpringBoot로 SpringSecurity 기반의 JWT 토큰 구현하기 (0) | 2023.09.05 |
Spring ) Blacklist (0) | 2023.07.19 |
Spring ) Spring Security 구현 순서 (0) | 2023.07.19 |
Spring ) Java Spring @Override annotation 이란? @Override 사용법 (0) | 2023.07.19 |