Spring Security: Auditing Spring Data Entities
Spring Data enables you track who modified an entity and when, with just a few annotations. When combined with Spring Security, you can set this metadata based on the active user.
This post is part of a series of blog posts on Spring Security; the code can be found on GitHub.
Implementation
This project only looks at persistence and setting the audit metadata.
It uses the active user to lookup an Author
when saving a Blogpost
entity.
Entities & repositories
The Author
class extends AbstractPersistable
to get a generated primary key with proper equals(Object)
and hashCode()
implementations.
@Data
@Entity
@EntityListeners(AuditingEntityListener.class)
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class Author extends AbstractPersistable<Long> {
private String name;
@CreatedDate
@Temporal(TemporalType.TIMESTAMP)
private Date createdDate;
}
The BlogPost
class in turn extends AbstractAuditable
with type arguments <Author, Long>
, to add Author createdBy()
and Date createdDate()
, as well as Author modifiedBy()
and Date modifiedDate()
methods.
In the database the relation between BlogPost
and Author
tables will be captured as a foreign key.
@Data
@Entity
@EntityListeners(AuditingEntityListener.class)
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class Blogpost extends AbstractAuditable<Author, Long> {
private String title;
private String content;
private boolean published;
}
Both entities are annotated with @EntityListeners(AuditingEntityListener.class)
, which is a JPA entity listener to capture auditing information on persisting and updating entities.
Our repositories merely extend the Spring Data Repository
interface to define the save
and findByName
methods.
Enable JPA Auditing
We define a AuditSecurityConfiguration
class, which we annotate with @EnableJpaAuditing
to enable auditing in JPA via annotation configuration.
This will trigger Spring Data into setting the audit metadata on your entities.
@Configuration
@EnableJpaAuditing
public class AuditSecurityConfiguration {
@Bean
AuditorAware<Author> auditorAware(AuthorRepository repo) {
// Lookup Author instance corresponding to logged in user
return () -> Optional.ofNullable(SecurityContextHolder.getContext())
.map(SecurityContext::getAuthentication)
.filter(Authentication::isAuthenticated)
.map(Authentication::getName)
.flatMap(repo::findByName);
}
}
The AuditSecurityConfiguration
class defines a single AuditorAware<Author>
bean, needed to lookup the Author
entity corresponding to the active user.
Note that the return type matches the auditing type argument set on the Blogpost
class.
Tests
Our AuditSecurityConfigurationTest
ties together all elements to ensure audit metadata is looked up and set when saving a Blogpost
entity.
There are additional tests that verify the current behavior when an Author
can not be found.
Conclusion
With audit information automatically set by Spring Data, you’re perfectly set to track who modified entities and when. This audit information can then also be used in owner access restrictions if desired.