我按照本指南使用 ACL 设置安全性,效果很好。之后我还尝试在 WebSecurityConfigurerAdapter 中实现 ACL。所以我设置了一个 bean,它会创建一个 DefaultWebSecurityExpressionHandler:
@Bean
public DefaultWebSecurityExpressionHandler webExpressionHandler(AclPermissionEvaluator aclPermissionEvaluator) {
final DefaultWebSecurityExpressionHandler webSecurityExpressionHandler = new DefaultWebSecurityExpressionHandler();
AclPermissionEvaluator permissionEvaluator = aclPermissionEvaluator();
webSecurityExpressionHandler.setPermissionEvaluator(permissionEvaluator);
return webSecurityExpressionHandler;
}
我会将它应用于我的 WebSecurityConfigurerAdapter 中的 HttpSecurity:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.expressionHandler(webExpressionHandlerWithACL)
.antMatchers(HttpMethod.PUT, "/api/user/users/{ID}").access("isAuthenticated() and hasPermission(#ID, 'xxx.xxx.xxx.xxx.xxx.UserDto', 'write')")
.anyRequest().authenticated()
.and()
.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint)
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(filter, UsernamePasswordAuthenticationFilter.class);
}
但这只是行不通。这个完全相同的表达式在 @PreAuthorize 标记中起作用,但在这里它不起作用。我调试了一下,发现准确的故障点在Spring提供的JdbcAclServiceImpl类中,方法如下:
@Override
public Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids)
throws NotFoundException {
Map<ObjectIdentity, Acl> result = this.lookupStrategy.readAclsById(objects, sids);
// Check every requested object identity was found (throw NotFoundException if
// needed)
for (ObjectIdentity oid : objects) {
if (!result.containsKey(oid)) {
throw new NotFoundException("Unable to find ACL information for object identity '" + oid + "'");
}
}
return result;
}
即使提供的参数与我使用 @PreAuthorize 标记时相同,result.containsKey(oid)
但即使我可以在调试器中看到它并且我看到oid
应该匹配它,也只是无法找到 acl。
所以我的问题是:Spring Security ACL 是否应该工作以保护路由,还是仅用于保护方法?
顺便说一句,我正在使用 Spring Boot 2.5.5