gre*_*gor 15 spring hibernate jpa spring-security spring-data
我们在应用程序中使用Hibernate/JPA,Spring,Spring Data和Spring Security.我有一个User
使用JPA映射的标准实体.而且,我有一个UserRepository
public interface UserRepository extends CrudRepository<User, Long> {
List<User> findByUsername(String username);
}
Run Code Online (Sandbox Code Playgroud)
它遵循Spring Data约定来命名查询方法.我有一个实体
@Entity
public class Foo extends AbstractAuditable<User, Long> {
private String name;
}
Run Code Online (Sandbox Code Playgroud)
我想使用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;
}
}
Run Code Online (Sandbox Code Playgroud)
当我创建一个方法
@Transactional
public void createFoo() {
Foo bar = new Foo();
fooRepository.save(foo);
}
Run Code Online (Sandbox Code Playgroud)
所有内容都正确连接并且FooRepository
是Spring Data CrudRepository
.然后StackOverflowError
抛出a ,因为调用findByUsername
似乎触发hibernate将数据刷新到数据库,触发AuditingEntityListener
谁调用AuditorService#getCurrentAuditor
再次触发刷新等等.
如何避免这种递归?加载User
实体是否有"规范方式" ?或者有没有办法阻止Hibernate/JPA刷新?
gre*_*gor 14
解决方案不是User
在AuditorAware
实现中获取记录.这会触发所描述的循环,因为select查询会触发刷新(这是因为Hibernate/JPA希望在执行select之前将数据写入数据库以提交事务),这会触发调用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;
}
}
Run Code Online (Sandbox Code Playgroud)
此外,我改变了我UserDetailsService
的加载User
和创建UserAwareUserDetails
.现在可以User
通过以下方式访问实例SercurityContextHolder
:
@Override
public User getCurrentAuditor() {
return ((UserAwareUserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUser();
}
Run Code Online (Sandbox Code Playgroud)
Ana*_*hah 11
我得到了同样的问题,我所做的只是改变findByUsername(username)
方法上的传播Propagation.REQUIRES_NEW
,我怀疑这是交易的问题,所以我改为使用新的交易,这对我来说很有效.我希望这可以提供帮助.
@Repository
public interface UserRepository extends JpaRepository<User, String> {
@Transactional(propagation = Propagation.REQUIRES_NEW)
List<User> findByUsername(String username);
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
13506 次 |
最近记录: |