1. 概述

Spring Security 为与 Spring Data 的集成提供了强大支持。前者负责应用的安全管控,后者则提供便捷的数据库访问能力。本文将探讨 如何通过 Spring Data 与 Spring Security 的集成,实现更精细化的用户级数据查询

2. Spring Security + Spring Data 配置

Spring Data JPA 入门 中我们已了解 Spring Data 的基础配置。要同时启用 Spring Security 和 Spring Data,可采用 Java 或 XML 配置方式。

2.1. Java 配置

参考 Spring Security 登录表单(第4-5节),可通过注解方式添加 Spring Security:

@EnableWebSecurity
public class WebSecurityConfig {
    // Bean 定义
}

其他配置细节包括过滤器、Bean 和安全规则的定义。要启用 Spring Data 与 Spring Security 的集成,只需在 WebSecurityConfig 中添加以下 Bean:

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

该配置会自动激活类上注解的 Spring Data 特定表达式解析。

2.2. XML 配置

XML 配置需先引入 Spring Security 命名空间:

<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>

与 Java 配置类似,在 XML 中添加 SecurityEvaluationContextExtension Bean:

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

定义该 Bean 后,Spring Security 的通用表达式(如 principalauthenticationisAnonymous()hasRole([role])isAuthenticated() 等)即可在 Spring Data 查询中使用。

3. 实战案例

3.1. 限制用户字段更新

此场景要求仅允许当前认证用户更新自己的 lastLogin 字段。当触发 updateLastLogin 方法时,应只更新当前登录用户的信息。在 UserRepository 接口中添加如下查询:

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

⚠️ 若未集成 Spring Security,通常需要显式传递用户名参数。但在此场景下,错误凭证会导致登录失败,无需额外验证访问权限。

3.2. 分页获取用户专属内容

当需要从数据库获取当前认证用户拥有的数据时(如 Twitter 应用中展示用户创建或点赞的推文),Spring Data 与 Spring Security 的组合能极大简化开发:

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);
}

为实现分页功能,TweetRepository 继承了 PagingAndSortingRepository。自 Spring Data Commons 3.0 起,接口结构重构后(核心接口为 Repository),若需 CRUD 操作需显式继承 CrudRepository 等专用接口。

4. 总结

Spring Data 与 Spring Security 的集成为 Spring 应用中的认证状态管理提供了极大灵活性。本文展示了如何将 Spring Security 集成到 Spring Data 中。更多高级功能可参考我们的 Spring DataSpring Security 系列文章。

完整代码示例请访问 GitHub


原始标题:Spring Data with Spring Security