如何让AuditorAware从Spring Security将CreatedBy存储为UUID



我正试图从我的登录用户那里获得UUID,并将其存储为"CreatedBy";以及";LastUpdatedBy";而不仅仅是字符串。然而,我得到了一个铸造错误:

类java.lang.String不能强制转换为类com.example.lims.contacter.container

下面的所有代码。。。谢谢

大编辑:

我更改了ApplicationUser以实现SpringSecurity中的UserDetails,并将合法的映射关系添加到我的BaseEntity中。现在我得到了一个新的例外。我确信这与我从SecurityAuditAware返回的内容有关。我不知道如何让它返回正确的ApplicationUser实例。

java.lang.ClassCastException:类java.lang.String不能强制转换为类com.example.lims.user.ApplicationUser(java.lang.Sstring在加载程序'bootstrap'的模块java.base中;me.tmpjr.lims.user.ApplicationUser在加载程序org.springframework.boot.devtools.restart.classloader.RestartClassLoader@3d3e8a83的未命名模块中(在com.example.lims.security.SecurityAuditorAware.getCurrentAuditor(SecurityAuditorAware.java:20(~[classes/:na]

架构:

CREATE TABLE IF NOT EXISTS "containers" (
id uuid NOT NULL,
container_name VARCHAR(100) NOT NULL,
created_by UUID NOT NULL,
created_at TIMESTAMP WITHOUT TIME ZONE NOT NULL,
updated_by UUID,
updated_at TIMESTAMP WITHOUT TIME ZONE,
PRIMARY KEY (id)
);
CREATE TABLE IF NOT EXISTS "users" (
id uuid NOT NULL,
username VARCHAR(100) NOT NULL,
password VARCHAR(100) NOT NULL,
created_by UUID,
created_at TIMESTAMP WITHOUT TIME ZONE NOT NULL,
updated_by UUID,
updated_at TIMESTAMP WITHOUT TIME ZONE,
PRIMARY KEY (id)
);

BaseEntity AuditorAware:

@Data
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class BaseEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
protected UUID id;
@CreatedDate
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "created_at")
protected Date createdAt;
@LastModifiedDate
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "updated_at")
protected Date updatedAt;
@CreatedBy
@JoinColumn(name = "created_by", nullable = true, insertable = true, updatable = false)
@ManyToOne
protected ApplicationUser createdBy;
@LastModifiedBy
@JoinColumn(name = "updated_by", nullable = true, insertable = false, updatable = false)
@ManyToOne
protected ApplicationUser updatedBy;
}

应用程序用户:

@Data
@EqualsAndHashCode(callSuper = true)
@Entity
@Valid
@Table(name = "users")
@NoArgsConstructor
public class ApplicationUser extends BaseEntity implements UserDetails 
{
@Column(nullable = false)
private String username;
@Column(nullable = false)
private String password;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return null;
}
@Override
public boolean isAccountNonExpired() {
return false;
}
@Override
public boolean isAccountNonLocked() {
return false;
}
@Override
public boolean isCredentialsNonExpired() {
return false;
}
@Override
public boolean isEnabled() {
return false;
}
}

返回ApplicationUser:的安全AuditorAware实现

@Component
public class SecurityAuditorAware implements AuditorAware<ApplicationUser> {
public Optional<ApplicationUser> getCurrentAuditor() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth == null || !auth.isAuthenticated()) {
return Optional.empty();
}
// THIS is where I think it's going wrong.. what to return here? How to return ApplicationUser?
return Optional.ofNullable((ApplicationUser) auth.getPrincipal());
}
}

UserDetailsServiceImpl:

@RequiredArgsConstructor
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
private final ApplicationUserRepository userRepository;
@Override
public ApplicationUser loadUserByUsername(String username) throws UsernameNotFoundException {
ApplicationUser applicationUser = userRepository.findByUsername(username);
if (applicationUser == null) {
throw new UsernameNotFoundException(username);
}
return applicationUser;
}
}

Bean配置:

@Configuration
@EnableJpaAuditing(auditorAwareRef = "auditorAware")
public class PersistenceConfig {
@Bean
public AuditorAware<ApplicationUser> auditorAware() {
return new SecurityAuditorAware();
}
}

完全例外:

java.lang.ClassCastException: class java.lang.String cannot be cast to class com.example.lims.user.ApplicationUser (java.lang.String is in module java.base of loader 'bootstrap'; com.example.lims.user.ApplicationUser is in unnamed module of loader org.springframework.boot.devtools.restart.classloader.RestartClassLoader @3d3e8a83)
at com.example.lims.security.SecurityAuditorAware.getCurrentAuditor(SecurityAuditorAware.java:21) ~[classes/:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:564) ~[na:na]

有效的解决方案

我相信我已经发现了问题。由于我使用的是UsernamePasswordAuthenticationToken,getPrinciple不返回UserDetails对象。我根本无法将其强制转换为我的自定义Entity类。但是,如果我在SecurityAuditorAware中手动使用存储库搜索并直接返回,它就可以工作了!

@Component
@RequiredArgsConstructor
public class SecurityAuditorAware implements AuditorAware<ApplicationUser> {
private final ApplicationUserRepository userRepository;
public Optional<ApplicationUser> getCurrentAuditor() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth == null || !auth.isAuthenticated()) {
return Optional.empty();
}
return Optional.ofNullable((ApplicationUser) userRepository.findByUsername((auth.getName())));
}
}
change your id data type to Long
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
protected Long id;

然后你的安全审计员应该像这个

public class SpringSecurityAuditorAware implements AuditorAware<Long> {

@Override
@Transactional(readOnly = false, propagation = Propagation.SUPPORTS)
public Long getCurrentAuditor() {
Authentication auth = 
SecurityContextHolder.getContext().getAuthentication();

return auth.getPrincipal().getId();
}
}

最新更新