当根据谁访问哪个域对象做出安全决策时,您可能需要一个自定义的访问决策投票者。幸运的是,Spring Security有很多这样的选项来实现访问控制列表(ACL)约束。
代码可以在GitHub上找到:https://github.com/timtebeek/spring-security-samples/
实现
我们将探索一个用户共享电子表格的系统,每个电子表格的访问权限单独存储。我们已经尽可能简单地对权限存储进行了显式建模;想象一下,它在调用其他地方的记录系统。请注意,在这个简化的实现中,访问决定是二进制的:要么有访问权,要么没有。在这个实现中,读/写访问权没有区别。
安全注释
打开SpreadsheetService会显示一个用@Secured
注释的方法。
@Secured("com.jdriven.model.Spreadsheet")
public void read(Spreadsheet spreadsheet) {
log.info("Reading {}", spreadsheet);
}
@Secured
注解参数是我们要限制的域对象访问的完全限定类名。该方法具有相同类型的参数,这是我们将保护的特定实例。
方便地,@Secured
注解不需要按名称引用参数;它可以在我们的AccessDecisionVoter
中单独按类型检索。
投票机制
访问决策由AccessDecisionManager
做出,它将授权给已配置的AccessDecisionVorters
列表。投票者可以根据自己的应用程序逻辑选择批准或拒绝特定的方法调用。如果投票人不能决定某个特定的方法调用,它可以选择弃权,将决定权留给其他投票人。默认情况下,您将获得基于确认的访问决策管理器,该管理器允许在只有一个投票人投票授予访问权限时调用方法,而不管是否有投票拒绝访问。
我们的四个目的是,我们需要一个自定义投票者,根据存储的访问记录验证用户对电子表格的访问。我们通过扩展AbstractAclVoter
来实现这一点,对于已配置的已处理域对象类和方法调用,AbstractAclVoter
可以查找参数域对象实例。我们将实现投票方法,该方法由经过身份验证的用户、安全方法调用和一组ConfigAttributes
传递。
@Override
public int vote(Authentication authentication, MethodInvocation methodInvocation, Collection<ConfigAttribute> attributes) {
for (ConfigAttribute configAttribute : attributes) {
if (supports(configAttribute)) {
User principal = (User) authentication.getPrincipal();
Spreadsheet domainObjectInstance = (Spreadsheet) getDomainObjectInstance(methodInvocation);
return hasSpreadsheetAccess(principal, domainObjectInstance) ? ACCESS_GRANTED : ACCESS_DENIED;
}
}
return ACCESS_ABSTAIN;
}
我们的投票者被传递一个或多个ConfigAttributes
,就像传递给@Secured
注释本身一样,我们通过调用布尔支持(ConfigAttribute
)来验证它:
@Override
public boolean supports(ConfigAttribute attribute) {
return getProcessDomainObjectClass().getName().equals(attribute.getAttribute());
}
考虑到这些实现,只有当ConfigAttribute
与配置的ProcessDomainObjectClass
不匹配时,投票者才会弃权。根据存储的访问记录,在所有其他情况下,投票人将投票批准或拒绝访问。
配置
我们需要配置应用程序的两个部分,以便触发自定义访问决策投票者逻辑。
首先,我们需要通过@EnableGlobalMethodSecurity(securedEnabled=true)
激活@Secured
注释,这是在AccessDecisionConfiguration
中完成的。
其次,我们需要将电子表格AccessDecisionVoter
添加到AccessDecisionManager
考虑的决策投票者列表中。为此,我们扩展了GlobalMethodSecurity
配置以覆盖AccessDecisionManager AccessDecisionManager()
。我们称之为super.accessDecisionManager()
获取默认的基于确认的访问决策管理器,只需在末尾添加我们自己的投票人。
如果您需要保护多个域对象类型,可以很容易地向列表中添加更多投票者。
测验
我们的电子表格AccessDecisionVoterit
测试使用模拟用户Alice和Bob,以及恶意的第三用户Eve,他们都试图访问单个电子表格。
您可以看到,对电子表格的访问遵守每个测试开始时存储的规则:
- Alice可以访问电子表格。
- Bob还可以访问电子表格。
- Eve无法访问电子表格,因为她收到了
AccessDeniedException
。
除特别注明外,本站所有文章均为老K的Java博客原创,转载请注明出处来自https://javakk.com/2582.html
暂无评论