Comment mettre en œuvre AuditorAware avec Spring Data JPA et de la Sécurité Printemps?
Nous utiliser Hibernate/JPA, le printemps, le Printemps des Données et de la Sécurité Printemps dans notre application. J'ai une User
entité qui est mappé à l'aide de JPA. De plus, j'ai un UserRepository
public interface UserRepository extends CrudRepository<User, Long> {
List<User> findByUsername(String username);
}
qui suit le Printemps de Données de la convention pour nommer les méthodes de requête. J'ai une entité
@Entity
public class Foo extends AbstractAuditable<User, Long> {
private String name;
}
Je veux utiliser de Printemps de l'audit des Données de soutien. (Comme descripe ici.) J'ai donc créé un AuditorService
comme suit:
@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;
}
}
Lorsque je crée une méthode
@Transactional
public void createFoo() {
Foo bar = new Foo();
fooRepository.save(foo);
}
Où tout est correctement câblé et FooRepository
une source de Données CrudRepository
. Puis un StackOverflowError
est jeté depuis l'appel à findByUsername
semble déclencher d'hibernation pour purger les données de la base de données qui déclenche AuditingEntityListener
qui appelle AuditorService#getCurrentAuditor
qui déclenche une nouvelle fois une couleur, et ainsi de suite.
Comment éviter cette récursivité? Est-il une "manière canonique" pour charger le User
entité? Ou est-il un moyen pour empêcher Hibernate/JPA, la purge?
Vous devez vous connecter pour publier un commentaire.
La solution est de ne pas récupérer les
User
enregistrement dans leAuditorAware
mise en œuvre. Cela déclenche le décrit en boucle, depuis une requête select déclenche une chasse d'eau (c'est le cas depuis Hibernate/JPA, veut écrire les données dans la base de données pour valider la transaction avant l'exécution de la sélection), ce qui déclenche un appel àAuditorAware#getCurrentAuditor
.La solution est de stocker les
User
enregistrement dans leUserDetails
prévue pour le Printemps de Sécurité. J'ai donc créé ma propre mise en œuvre:De plus, j'ai changé mon
UserDetailsService
pour charger leUser
et de créerUserAwareUserDetails
. Maintenant, il est possible d'accéder à laUser
exemple par le biais de laSercurityContextHolder
:User
n'était pas de cet utilisateurorg.springframework.security.core.userdetails.User
mais laUser
créé pour être enregistré dans la base de données. Alors que db-User
est celui que vous devez enregistrer dans votreUserAwareUserDetails
.J'ai eu le même problème et ce que j'ai fait était juste changer la propagation sur la
findByUsername(username)
méthode pourPropagation.REQUIRES_NEW
, je me doutais que c'était un problème avec les transactions, donc j'ai changé pour une nouvelle transaction et qui a bien fonctionné pour moi. J'espère que cela peut vous aider.Il semble que vous utilisez une entité Utilisateur pour deux choses différentes:
Je pense que ce sera mieux pour préparer un spécial AuditableUser à des fins d'audit (il va avoir le même nom d'utilisateur que l'Utilisateur d'origine).
Considérons le cas suivant: vous voulez supprimer un Utilisateur de la base de données. Si tous vos audit, les objets sont liés à l'Utilisateur alors qu'ils seront un) lâche auteur b) peut être supprimé par la cascade de trop (dépend de la façon dont le lien est mis en œuvre). Pas sûr que vous le souhaitez.
Donc, en utilisant des AuditableUser, vous aurez:
Pour être honnête, Vous n'avez pas réellement besoin l'un de l'autre entité.
Par exemple, j'ai eu le même problème et je l'ai résolu de la manière suivante:
Où SUser est à la fois la classe que j'utilise pour l'audit ainsi que pour la sécurité.
J'avais peut-être différents cas d'utilisation que le Vôtre et mon approche sera supprimé après, mais il peut être résolu comme ça.