当前位置: 首页 > 面试题库 >

如何使用Spring Data JPA和Spring Security实施AuditorAware?

嵇俊德
2023-03-14
问题内容

我们在应用程序中使用Hibernate / JPA,Spring,Spring Data和Spring
Security。我有一个User使用JPA映射的标准实体。此外,我有一个UserRepository

public interface UserRepository extends CrudRepository<User, Long> {
    List<User> findByUsername(String username);
}

它遵循Spring Data约定来命名查询方法。我有一个实体

@Entity
public class Foo extends AbstractAuditable<User, Long> {
    private String name;
}

我想使用Spring Data审核支持。(如此处所述。)因此,我创建了一个AuditorService如下:

@Service
public class AuditorService implements AuditorAware<User> {

    private UserRepository userRepository;

    @Override
    public User getCurrentAuditor() {
        String username = SecurityContextHolder.getContext().getAuthentication().getName();
        List<User> users = userRepository.findByUsername(username);
        if (users.size() > 0) {
            return users.get(0);
        } else {
            throw new IllegalArgumentException();
        }
    }

    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }
}

当我创建一个方法时

@Transactional
public void createFoo() {
    Foo bar = new Foo(); 
    fooRepository.save(foo);
}

一切都正确接线的地方FooRepository是Spring Data
CrudRepository。然后,将StackOverflowError引发a
,因为对的调用findByUsername似乎触发了hibernate,以将数据刷新到数据库,从而触发了AuditingEntityListener谁的调用AuditorService#getCurrentAuditor,再次触发了刷新等。

如何避免这种递归?是否有“规范的方式”加载User实体?还是有办法防止Hibernate / JPA刷新?


问题答案:

解决方案是不获取实现中的User记录AuditorAware。这会触发所描述的循环,因为选择查询会触发刷新(这种情况是因为Hibernate /
JPA希望在执行选择之前将数据写入数据库以提交事务),从而触发对的调用AuditorAware#getCurrentAuditor

解决方案是将User记录存储在UserDetails提供给Spring Security的文件中。因此,我创建了自己的实现:

public class UserAwareUserDetails implements UserDetails {

    private final User user;
    private final Collection<? extends GrantedAuthority> grantedAuthorities;

    public UserAwareUserDetails(User user) {
        this(user, new ArrayList<GrantedAuthority>());
    }

    public UserAwareUserDetails(User user, Collection<? extends GrantedAuthority> grantedAuthorities) {
        this.user = user;
        this.grantedAuthorities = grantedAuthorities;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return grantedAuthorities;
    }

    @Override
    public String getPassword() {
        return user.getSaltedPassword();
    }

    @Override
    public String getUsername() {
        return user.getUsername();
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }

    public User getUser() {
        return user;
    }
}

此外,我更改UserDetailsService了加载User并创建UserAwareUserDetails。现在可以User通过以下方式访问实例SercurityContextHolder

@Override
public User getCurrentAuditor() {
    return ((UserAwareUserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUser();
}


 类似资料:
  • 我正在学习springsecurity(基于java的配置),我无法使注销正常工作。当我点击注销时,我看到URL更改为http://localhost:8080/logout并获取“HTTP 404-/logout”。登录功能工作正常(即使使用自定义登录表单),但问题是注销,我怀疑重定向的url“localhost:8080/logout”应该类似于“localhost:8808/springte

  • 在Perl中,使用Moo,可以围绕sub实现sub,它将围绕类中的其他方法。 如何在Raku中实现这种行为,最好使用角色?

  • 我正在尝试实现身份验证 可以请求任何微服务的API网关。 用户微服务-我存储所有用户的地方。实现在此微服务中对用户进行身份验证。按应有的方式工作,登录路由返回我用于在此微服务中对用户进行身份验证的令牌。 其他5个微服务,未经任何身份验证或授权。 问题是:使用身份验证的正确方法是什么

  • 我有一个结构如下的项目。 是我的主要应用程序,而和是导入到Project中的两个库。使用了的一些类,使用了的一些类。 在的文件中,我使用了。一切正常。但是,如果我用替换,它就不能从导入类。它给出错误。

  • 本文向大家介绍如何使用SpringSecurity保护程序安全,包括了如何使用SpringSecurity保护程序安全的使用技巧和注意事项,需要的朋友参考一下 首先,引入依赖: 引入此依赖之后,你的web程序将拥有以下功能: 所有请求路径都需要认证 不需要特定的角色和权限 没有登录页面,使用HTTP基本身份认证 只有一个用户,名称为user 配置SpringSecurity springsecur

  • 问题内容: 在简要回顾了Go语言规范,有效的Go和Go内存模型之后,我仍然不清楚Go通道是如何工作的。 它们是什么样的结构?它们的行为有点像线程安全队列/数组。 它们的实现取决于体系结构吗? 问题答案: 通道的源文件位于/src/pkg/runtime/chan.go中(从您的源代码根目录开始)。 是通道的中央数据结构,带有发送和接收链接列表(持有指向其goroutine和data元素的指针)和一