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 的通用表达式(如 principal
、authentication
、isAnonymous()
、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 Data 和 Spring Security 系列文章。
完整代码示例请访问 GitHub。