1. Overview

Spring Security provides a good support for integration with Spring Data. While the former handles security aspects of our application, the latter provides convenient access to the database containing the application’s data.

In this article, we’ll discuss how Spring Security can be integrated with Spring Data to enable more user-specific queries.

2. Spring Security + Spring Data Configuration

In our introduction to Spring Data JPA, we saw how to setup Spring Data in a Spring project. To enable spring security and spring data, as usual, we can adopt either the Java or XML-based configuration.

2.1. Java Configuration

Recall that from Spring Security Login Form (sections 4 & 5), we can add Spring Security to our project using the annotation based configuration:

@EnableWebSecurity
public class WebSecurityConfig {
    // Bean definitions
}

Other configuration details would include the definition of filters, beans, and other security rules as required.

To enable Spring Data in Spring Security, we simply add this bean to WebSecurityConfig:

@Bean
public SecurityEvaluationContextExtension securityEvaluationContextExtension() {
    return new SecurityEvaluationContextExtension();
}

The above definition enables activation of automatic resolving of spring-data specific expressions annotated on classes.

2.2. XML Configuration

The XML-based configuration begins with the inclusion of the Spring Security namespace:

<beans:beans xmlns="http://www.springframework.org/schema/security"
  xmlns:beans="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
  http://www.springframework.org/schema/security
  http://www.springframework.org/schema/security/spring-security.xsd">
...
</beans:beans>

Just like in the Java-based configuration, for the XML or namespace based configuration, we’d add SecurityEvaluationContextExtension bean to the XML configuration file:

<bean class="org.springframework.security.data.repository
  .query.SecurityEvaluationContextExtension"/>

Defining the SecurityEvaluationContextExtension makes all the common expressions in Spring Security available from within Spring Data queries.

Such common expressions include principal, authentication, isAnonymous(), hasRole([role]), isAuthenticated, etc.

3. Example Usage

Let’s consider some use cases of Spring Data and Spring Security.

3.1. Restrict AppUser Field Update

In this example, we’ll look at restricting App**User‘s lastLogin field update to the only currently authenticated user.

By this, we mean that anytime updateLastLogin method is triggered, it only updates the lastLogin field of the currently authenticated user.

To achieve this, we add the query below to our UserRepository interface:

@Query("UPDATE AppUser u SET u.lastLogin=:lastLogin WHERE" 
  +" u.username = ?#{ principal?.username }")
@Modifying
@Transactional
void updateLastLogin (@Param("lastLogin") Date lastLogin);

Without Spring Data and Spring Security integration, we’d normally have to pass the username as an argument to updateLastLogin.

In a case where the wrong user credentials are provided, the login process will fail and we do not need to bother about ensuring validation of access.

3.2. Fetch Specific AppUser’ Content With Pagination

Another scenario where Spring Data and Spring Security work perfectly hand-in-hand is a case where we need to retrieve content from our database that is owned by the currently authenticated user.

For instance, if we have a tweeter application, we may want to display tweets created or liked by current user on their personalized feeds page.

Of course, this may involve writing queries to interact with one or more tables in our database. With Spring Data and Spring Security, this is as simple as writing:

public interface TweetRepository extends PagingAndSortingRepository<Tweet, Long>, CrudRepository<Tweet, Long> {
    @Query("SELECT twt FROM Tweet twt JOIN twt.likes AS lk WHERE lk = ?#{ principal?.username }" +
      " OR twt.owner = ?#{ principal?.username }")
    Page<Tweet> getMyTweetsAndTheOnesILiked(Pageable pageable);
}

Because we want our results paginated, our TweetRepository extends PagingAndSortingRepository in the above interface definition.

Starting with Spring Data Commons 3.0, there were some refactoring decoupling some of the interfaces: CrudRepository, ListCrudRepository, PagingAndSortingRepository and ListPagingAndSortingRepository having the central interface Repository. One of the disadvantages of this is that, in case you need CRUD operations you have to extend CRUD-specific interface.

4. Conclusion

Spring Data and Spring Security integration bring a lot of flexibility to managing authenticated states in Spring applications.

In this session, we’ve had a look at how to add Spring Security to Spring Data. More about other powerful features of Spring Data or Spring Security can be found in our collection of Spring Data and Spring Security articles.

As usual, code snippets can be found over on GitHub.