작성일시, 수정일시, 작성자, 수정자 등을 모든 entity에 추가하기에는 코드가 길어질 수 있어 따로 분리하여 작성하기 위해 Auditing을 사용해준다.
Application
@SpringBootApplication
@EnableJpaAuditing
public class FreeMarketApplication {
public static void main(String[] args) {
SpringApplication.run(FreeMarketApplication.class, args);
}
// AuditorAware 빈 등록 - 현재 인증된 사용자의 ID를 제공
@Bean
public AuditorAware<Long> auditorProvider() {
return new AuditorAwareImpl();
}
}
CustomUserDetails
@Getter
public class CustomUserDetails implements UserDetails {
private final Long userId;
private final String email;
private final String password;
private final String role;
private final boolean enabled;
public CustomUserDetails(Long userId, String email, String password, String role, boolean enabled) {
this.userId = userId;
this.email = email;
this.password = password;
this.role = role;
this.enabled = enabled;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
// role 값에 "ROLE_" 접두사가 없으면 추가
String authority = this.role.startsWith("ROLE_") ? this.role : "ROLE_" + this.role;
return Collections.singleton(new SimpleGrantedAuthority(authority));
}
@Override
public String getPassword() {
return this.password;
}
@Override
public String getUsername() {
// Spring Security의 username으로 email을 사용
return this.email;
}
@Override
public boolean isAccountNonExpired() {
// 계정 만료 여부: true는 만료되지 않음을 의미
return true;
}
@Override
public boolean isAccountNonLocked() {
// 계정 잠금 여부: true는 잠기지 않음을 의미
return true;
}
@Override
public boolean isCredentialsNonExpired() {
// 자격 증명 만료 여부: true는 만료되지 않음을 의미
return true;
}
@Override
public boolean isEnabled() {
// 계정 활성화 여부
return this.enabled;
}
}
CustomUserDetails 클래스는 이후 Security 관련 코드에서도 사용할 것이다.
AuditorAwareImpl
public class AuditorAwareImpl implements AuditorAware<Long> {
@Override
public Optional<Long> getCurrentAuditor() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
// 인증 정보가 없거나 인증되지 않은 경우
if (authentication == null || !authentication.isAuthenticated()) {
return Optional.empty();
}
// 인증된 사용자 정보 추출
Object principal = authentication.getPrincipal();
if (principal instanceof CustomUserDetails) {
CustomUserDetails userDetails = (CustomUserDetails) principal;
return Optional.of(userDetails.getUserId());
}
return Optional.empty();
}
}
Security에서 사용자 정보를 추출하여 작성자, 수정자로 표시를 해준다.
BaseTimeEntity
@EntityListeners(AuditingEntityListener.class)
@MappedSuperclass
@Getter
public class BaseTimeEntity {
@CreatedDate
@Column(updatable = false)
private LocalDateTime createdDate;
@LastModifiedDate
private LocalDateTime updatedDate;
}
BaseEntity
@EntityListeners(AuditingEntityListener.class)
@MappedSuperclass
@Getter
public class BaseEntity extends BaseTimeEntity {
@CreatedBy
@Column(updatable = false)
private Long createdBy;
@LastModifiedBy
private Long modifiedBy;
}