Wie die Umsetzung AuditorAware mit Spring Data JPA und Spring Security?
Verwenden wir Hibernate/JPA, Spring, Spring Data und Spring Security in unserer Anwendung. Ich habe eine standard - User
Person, die abgebildet wird, die mit JPA. Weiter habe ich eine UserRepository
public interface UserRepository extends CrudRepository<User, Long> {
List<User> findByUsername(String username);
}
folgt der Frühling-Daten-Konvention für die Benennung von Methoden Abfragen. Ich habe eine Entität
@Entity
public class Foo extends AbstractAuditable<User, Long> {
private String name;
}
Will ich mit Spring Data auditing-support. (Als descripe hier.) Daher erstellte ich eine AuditorService
wie folgt:
@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;
}
}
Wenn ich eine Methode erstellen
@Transactional
public void createFoo() {
Foo bar = new Foo();
fooRepository.save(foo);
}
Wo alles ist richtig verkabelt und FooRepository
eine Feder befindet, die Daten CrudRepository
. Dann ein StackOverflowError
geworfen wird, da der Aufruf findByUsername
auszulösen scheint hibernate Spülen, um die Daten zur Datenbank, die Trigger AuditingEntityListener
wer ruft AuditorService#getCurrentAuditor
was wiederum löst einen flush und so weiter.
Wie Sie vermeiden, diese Rekursion? Gibt es eine "kanonische Weg" laden die User
Entität? Oder gibt es eine Möglichkeit zu verhindern, Hibernate/JPA von der Spülung?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Die Lösung ist nicht zu Holen die
User
Datensatz in derAuditorAware
Umsetzung. Dies löst die beschriebene Schleife, da eine select-Abfrage löst einen flush (dies ist der Fall, da Hibernate/JPA will schreiben der Daten in die Datenbank festschreiben der Transaktion vor der Ausführung der select), die löst ein AufrufAuditorAware#getCurrentAuditor
.Die Lösung ist die Speicherung der
User
Datensatz in derUserDetails
zur Verfügung gestellt Spring Security. Daher habe ich meine eigene Implementierung:Weiter, änderte ich meine
UserDetailsService
zu ladenUser
und erstellenUserAwareUserDetails
. Jetzt ist es möglich, den Zugriff auf dieUser
etwa durch dieSercurityContextHolder
:Ich habe das gleiche Problem und was ich Tat, war ändern Sie einfach die Verteilung auf die
findByUsername(username)
MethodePropagation.REQUIRES_NEW
ich vermutete, dass war ein problem mit den Transaktionen, so dass ich geändert, um eine neue Transaktion und die gut für mich gearbeitet. Ich hoffe, dass dies helfen kann.Sieht es aus wie Sie eine benutzerdefinierte Entität für zwei verschiedene Dinge:
Ich denke, es wird besser sein, um ein spezielles AuditableUser für audit-Zwecke (es werden identische Feld username original-Benutzer).
Betrachten Sie folgenden Fall: Sie löschen möchten einige Benutzer aus der Datenbank. Wenn alle Ihre Objekte überwachen verknüpft sind-Benutzer sind, dann werden Sie a) lose Autor b) kann gelöscht werden, indem Sie die Kaskade zu (hängt davon ab, wie die Verknüpfung implementiert ist). Nicht sicher, dass Sie es wollen.
So werden durch die Verwendung spezieller AuditableUser haben Sie:
Um ehrlich zu sein, Sie nicht wirklich erfordern, dass man einem anderen Unternehmen.
Zum Beispiel, ich hatte ähnliches problem und habe es behoben in folgender Weise:
Wo SUser ist sowohl die Klasse, die ich benutze für die überwachung als auch für die Sicherheit.
Vielleicht hatte ich verschiedene use-case als Deins und mein Ansatz nach gelöscht werden, aber es kann geklärt werden wie diese.