我正在编写一个库,它使用Spring Security 和方法安全性来检查用户是否获得执行特定操作的许可。这是对通常基于角色的安全性的补充,这导致了一个问题。
注解与此测试类中的注解类似:
@RestController
class TestController {
@RolesAllowed("ROLE_USER")
@Licensed("a")
public ResponseEntity<String> a() {
return ResponseEntity.ok("a");
}
@RolesAllowed("ROLE_USER")
@Licensed("b")
public ResponseEntity<String> b() {
return ResponseEntity.ok("b");
}
@RolesAllowed("ROLE_USER")
@Licensed("c")
public ResponseEntity<String> c() {
return ResponseEntity.ok("c");
}
}
处理注解似乎很简单,因为您添加了 customMethodSecurityDataSource
:
@EnableGlobalMethodSecurity(
securedEnabled = true,
jsr250Enabled = true,
prePostEnabled = true
)
@Configuration
public class LicenceSecurityConfiguration extends GlobalMethodSecurityConfiguration {
@Override protected MethodSecurityMetadataSource customMethodSecurityMetadataSource() {
return new LicensedAnnotationSecurityMetadataSource();
}
// more configurations
}
但问题在于spring的实现:
@Override
public Collection<ConfigAttribute> getAttributes(Method method, Class<?> targetClass) {
DefaultCacheKey cacheKey = new DefaultCacheKey(method, targetClass);
synchronized (this.attributeCache) {
Collection<ConfigAttribute> cached = this.attributeCache.get(cacheKey);
// Check for canonical value indicating there is no config attribute,
if (cached != null) {
return cached;
}
// No cached value, so query the sources to find a result
Collection<ConfigAttribute> attributes = null;
for (MethodSecurityMetadataSource s : this.methodSecurityMetadataSources) {
attributes = s.getAttributes(method, targetClass);
if (attributes != null && !attributes.isEmpty()) {
break;
}
}
// Put it in the cache.
if (attributes == null || attributes.isEmpty()) {
this.attributeCache.put(cacheKey, NULL_CONFIG_ATTRIBUTE);
return NULL_CONFIG_ATTRIBUTE;
}
this.logger.debug(LogMessage.format("Caching method [%s] with attributes %s", cacheKey, attributes));
this.attributeCache.put(cacheKey, attributes);
return attributes;
}
首先处理我的自定义元数据源,一旦它找到它识别的注解,它就会停止处理。具体而言,在此if块中:
if (attributes != null && !attributes.isEmpty()) {
break;
}
结果是我的 LicenceDecisionVoter
弃权票;毕竟,可能还有其他注解处理器来检查角色。因为没有更多的属性可以投票,只有 ACCESS_ABSTAIN
返回,并且根据spring的默认和推荐配置,访问被拒绝。角色从不被检查。
除了为spring自己的注解处理器(如 @Secured
和jsr-250注解?
或者说,将spring security用于此特定目的是错误的?
1条答案
按热度按时间jtoj6r0c1#
正如承诺的那样,解决方案是可行的。这比我想象的要多,而且代码可能有问题,因为它部分是从spring复制的,而且其中一些代码看起来很不可靠(或者至少intellij认为是这样)。
关键是要移除
GlobalMethodSecurityConfiguration
. 将此留给应用程序本身。(自动)配置类如下所示:书记官长:
最后,顾问:
后两个类是从spring复制和修改的。顾问是从
MethodSecurityMetadataSourceAdvisor
,这是一个在spring的人可能会看到的类,因为transient volatile
同步对象(我复制了它,因为我还不能确定它是否应该是final
相反),因为它有一个从未使用过的私有方法。