堆栈:
spring boot 2.7.15
spring-boot-starter-data-jpa 2.7.15
spring-data-envers 2.7.15
我有以下实体:
@Audited
@Entity
@EntityListeners(AuditingEntityListener.class)
public class MyUser{
}
使用审核员配置类
JpaAuditingConfiguration
:
@Configuration
@AutoConfigureAfter(name = "org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration")
@EnableJpaAuditing
public class JpaAuditingConfiguration {
@Bean
public AuditorAware<Long> auditorAware(MyUserService myUserService ) {
return myUserService::getCurrentUserId;
}
}
还有
MyUserService
班:
@Service
@RequiredArgsConstructor
public class MyUserService {
public Optional<Long> getCurrentUserId() {
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (principal instanceof OAuth2AuthenticatedPrincipal) {
// logic here
}
return Optional.empty();
}
}
我的问题来了:我有一个来自内部授权/身份验证框架的 Bean,它设置/丰富 spring 的
Authentication
对象,并且当用户在 UI 中登录时触发它。在这个 bean 方法中,一个实体被修改并持久化到数据库中:
public Set<String> retrieveUserAuthorities(String username) {
Optional<MyUser> userOptional = userRepository.findByUsername(username);
if (userOptional.isPresent()) {
MyUser user = userOptional.get();
// different setters for user
myUserService.saveUser(user); // <--- here is the problem
return ...
}
// ...
}
问题:
基本上,问题在于实体在设置Authentication
对象之前
被持久化到数据库中,因此当触发审计流程并到达方法
getCurrentUserId()
(其中
SecurityContextHolder.getContext().getAuthentication()
为空)时会得到一个NPE。就我而言,我希望
仅此数据库操作不被持久化,但该实体上的其他操作要持久化,因此删除Audited
或
@EntityListeners
不是一个选项。
principal
对象之前进行简单的空检查就可以解决问题。
public Optional<Long> getCurrentUserId() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null && principal instanceof OAuth2AuthenticatedPrincipal) {
// logic here
}
return Optional.empty();
}
在 Spring Security 中发现 authentication
对象为
null
并不奇怪。