Spring Security 结合 Spring 存储库来保护和验证网站的各个部分
Posted
技术标签:
【中文标题】Spring Security 结合 Spring 存储库来保护和验证网站的各个部分【英文标题】:Spring Security in conjuction with Spring repositories to secure and authenticate various parts of a website 【发布时间】:2016-08-31 15:06:40 【问题描述】:我正在寻找一个具体、严肃和完整的示例,说明如何在 Spring Boot 应用程序中使用 Spring 安全性,该应用程序使用 Spring data repositories 访问数据库并因此查询注册用户。
我已经看到,通过覆盖 configure
方法,它可以使用 Spring 安全性轻松保护一系列网页,例如使用以下选项:
http.authorizeRequests()
.antMatchers("/", "/css/**", "/js/**", "/vendor/**", "/templates/**")
.permitAll()
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
此代码可保护用户例如访问http://localhost:3000/home/users/
,但允许随后访问http://localhost:3000/login
或简单地访问http://localhost:3000
。
我一直在阅读有关 Spring 安全性的信息,但我不知道如何保护应用程序的不同部分,例如,当用户登录网站时,并禁止他从示例中访问http://localhost:3000/home/users/another_user
,通常用于控制登录用户对网站所有部分的访问。
我正在使用Spring data repositories 通过实体来操作数据库的数据。
您是否知道将 Spring 安全性与 Spring 存储库(以及必要时的其他工具)结合使用来保护(和验证)网站不同部分的示例? (视频)教程也可能有用。
感谢您的帮助。
注意:我查看了 sagan 网站的存储库,但要理解发生了什么非常复杂......
【问题讨论】:
【参考方案1】:如上所述,ACL 是一种选择,但另一种可能更简单的解决方案可能是在方法级别应用安全性。
请参阅第 15.3 节。
https://docs.spring.io/spring-security/site/docs/3.0.x/reference/el-access.html
所以假设你有一个 URL /users/123 ,其中 123 是当前用户,它委托给服务层方法来加载用户,那么我如何防止用户篡改 URL 并查看例如返回的数据。 /users/456.
一种方法是通过@PostAuthorize 注解应用方法级安全性:
@PostAuthorize("hasPermission(returnObject, null)")
public User findById(Long id)
return repository.findOne(id);
安全检查委托给 org.springframework.security.access.PermissionEvaluator 的实现
实现可能如下所示:
public class BasePermissionsEvaluator implements PermissionEvaluator
public boolean hasPermission(Authentication authentication, Object domainObject)
return hasPermission(authentication, domainObject, null);
@Override
public boolean hasPermission(Authentication authentication, Object domainObject, Object permission)
boolean hasPermission = true;
//User is my custom class representing a logged in user
//UserEntity is my custom interface implemented by entities associated with specific user
//If user is an Admin allow access
//Otherwise allow access if logged in user 'owns' the DomainObject instance
User user = (User) authentication.getPrincipal();
if(! user.isAdmin())
if (domainObject instanceof UserEntity)
User owner = ((UserEntity) domainObject).getOwner();
hasPermission = user.equals(owner);
return hasPermission;
@Override
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType,
Object permission)
return false;
PermissionEvaluator 的配置在 XML 中如下所示,因此您需要转换为 Java 配置:
<security:global-method-security
pre-post-annotations="enabled">
<security:expression-handler ref="expressionHandler"/>
</security:global-method-security>
<bean id="expressionHandler"
class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
<property name="permissionEvaluator" ref="permissionEvaluator" />
</bean>
<bean id="permissionEvaluator" class="com.mycompany.BasePermissionsEvaluator" />
以下概述了将 XML 配置转换为 Java 配置:
https://spring.io/blog/2013/07/04/spring-security-java-config-preview-method-security/#custom-method-security
因此,在您现有的安全配置类中,您应该添加:
@EnableGlobalMethodSecurity(prePostEnabled=true) //ADD THIS
public class MySecurityConfig
@Override
protected MethodSecurityExpressionHandler expressionHandler()
DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
//SET TO OUR CUSTOM PERMISSIONS HANDLER DETAILED ABOVE
expressionHandler.setPermissionEvaluator(new BasePermissionsEvaluator());
return expressionHandler;
【讨论】:
很抱歉很长时间没有对您的回答提供任何反馈,但我发现所有这些概念在我看来都不是微不足道和奇怪的,可能是因为我对这些东西总体上是新手,即使我已经在 Node 和 Express 中使用过passport.js
一次。我会有第一个问题或疑问。为什么我们要将这个PostAuthorize
应用到存储库方法中?这是因为在 Spring 控制器中我们可以使用这个特定的存储库方法(包含注释)来进行一些检查吗?
似乎 Spring 安全性使所有事情都变得非常复杂,只是对于简单的情况......根据我对 passport.js 的记忆,为应用程序设置安全性要容易得多,但我可能会也错了,或者,当时,我对自己所做的事情没有完整的看法......
我已将它放在存储库中,因为存储库正在返回评估程序所需的域对象的实例。我不能很好地在控制器上应用评估,因为这将完全返回其他东西。您可以在任何地方应用安全性,但这种特定情况会检查方法返回的域对象,因此存储库或服务层是合适的。登录的用户请求了一个实体。如果登录用户“拥有”请求的项目或具有管理员角色,则允许访问,否则拒绝访问。
好的。我会有另一个问题。到目前为止,我还没有配置文件,因为我使用的是 Spring Boot,它会为你做所有事情。我从来没有在没有 SpringBoot 的情况下使用过 Spring(但我可能也想学习它),所以我不知道将配置文件放在哪里,以及如何调用它们。官方教程好像用的是SpringBoot,而且很简单,所以很难理解到底应该怎么做。那么,我应该把这些 XML 规范放在哪里呢?
您正在使用 Java 配置,因此最好将 XML 转换为代码。这涉及向现有配置类添加注释并添加方法。确切的转换在这里详述spring.io/blog/2013/07/04/…:【参考方案2】:
这在 Spring Security 中称为访问控制,或“域对象安全”。
http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#domain-acls
你有很多阅读要做!
您可能希望将它与 Spring Data JPA 结合使用,以便 SDJ 只返回它应该返回的记录。这里有一个例子:
https://github.com/spring-projects/spring-data-examples/tree/master/jpa/security
基本上,您将向您的表添加一些“行所有者”信息,并让 SDJ 和 SS 一起工作以控制访问,例如:
@Query("select o from BusinessObject o where o.owner.emailAddress like ?#hasRole('ROLE_ADMIN') ? '%' : principal.emailAddress")
List<BusinessObject> findBusinessObjectsForCurrentUser();
另一种方法是使用支持行安全的数据库服务器,如 PostgreSQL,并在数据库中处理您的访问控制权。
【讨论】:
以上是关于Spring Security 结合 Spring 存储库来保护和验证网站的各个部分的主要内容,如果未能解决你的问题,请参考以下文章
Spring Security 结合了 Container Security 和 JWT Token
使用 Spring Security 在一个应用程序中结合数据库和 SAML 身份验证
spring security动态管理资源结合自定义登录页面
基于RBAC的权限控制浅析(结合Spring Security)