当前位置: 首页 > 知识库问答 >
问题:

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

锺超英
2023-03-14

我试图从登录用户那里获取UUID,将其存储为“CreatedBy”和“LastUpdatedBy”,而不仅仅是字符串。然而,我得到了一个演员错误:

类java。无法将lang.String转换为类com。实例林。容器容器

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

大编辑:

我更改了应用程序用户以实现来自SpringSecurity的用户详细信息,并向我的基本实体添加了合法的映射关系。现在我得到了一个新的异常。我很确定这与我从SecurityAuditAware返回的内容有关。我不知道如何让它返回正确的应用程序用户实例。

JAVAClassCastException:类java。无法将lang.String转换为类com。实例林。使用者ApplicationUser(java.lang.String位于加载程序“bootstrap”的模块java.base中;me.tmpjr.lims.user.ApplicationUser位于加载程序org.springframework.boot.devtools.restart.classloader.RestartClassLoader@3e8a83的未命名模块中)位于com。实例林。安全安全审计软件。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;
    }
}

豆配置:

@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对象。我无法将其转换为自定义实体类。然而,如果我在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())));
    }
}

共有1个答案

朱锐
2023-03-14
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();
    }
}
 类似资料:
  • 问题内容: 我已经看过所有类似的线程,阅读了文档,并尝试了许多组合来将空值存储在db中,并且每次都失败。 我正在使用MySQL。 我定义了一个字段。我从csv文件填充db,并且某些单元格没有值。Django文档说: 由于我正在与我一起工作,因此我希望将一个空字符串(csv中的一个空单元格)存储在db中。因此,我(认为)必须添加到该字段中。实际上,我已经尝试了更多: 每次我向数据库插入一个空字符串时

  • 本文向大家介绍如何将小端存储模式转为大端存储模式?相关面试题,主要包含被问及如何将小端存储模式转为大端存储模式?时的应答技巧和注意事项,需要的朋友参考一下

  • 我正试图从本地Spark集群将Spark DataFrame存储为Azure Blob存储中的CSV 首先,我用Azure Account/Account键设置配置(我不确定什么是正确的配置,所以我已经设置了所有这些) 似乎这个问题已经在数据库论坛上报告了!! 在Azure Blob上存储DataFrame的正确方法是什么?

  • 问题内容: 在我的应用程序中,我正在解析一个xml文件。在xml文件中,我有50个同名标签,现在我想将所有作为问题命名的标签存储为数组…。 在保存的那些标签中,我只希望在文本视图中放置一个问题标签…。 如何执行此操作.... pls帮助我..... 问题答案:

  • 问题内容: 如果已经将整个.class文件序列化为byte [],并假定该类的名称已知(与byte []一起传递),则如何转换byte []-> Class->然后将其加载到JVM,以便以后可以通过调用Class.forName()使用它? 注意: 之所以这样做,是因为我将.class发送到另一台主机,而主机的JVM不知道此.class。 问题答案: 我现在在测试中实际上正在使用类似的方法,将一组