我有一个Spring Boot应用程序,该应用程序使用spring安全性进行身份验证和授权。授权阶段需要在标准“基于授权”的授权之上自定义AccessDecisionVoter。 这是我的设置:
@Override
protected void configure(HttpSecurity http) throws Exception {
...
http.authorizeRequests()
.requestMatchers(getMatcherForAuthority1Urls())
.hasAuthority("AUTHORITY1")
.and().authorizeRequests()
.requestMatchers(getMatcherForAuthority2Urls())
.hasAuthority("AUTHORITY1")
.and().authorizeRequests()
.requestMatchers(getMatcherForAuthorities1and2Urls())
.hasAnyAuthority("AUTHORITY1", "AUTHORITY1");
http.authorizeRequests()
.regexMatchers(REGEX_PATTERN_URLS_THAT_NEED_AUTHORISATION).authenticated()
.accessDecisionManager(myAccessDecisionManager());
http.authorizeRequests()
.antMatchers(LOGIN_URL).permitAll();
}
@Bean
public AccessDecisionManager myAccessDecisionManager() {
List<AccessDecisionVoter<? extends Object>> decisionVoters
= Arrays.asList(
new WebExpressionVoter(), // votes for authorities
myAccessVoter); // my custom voter
return new UnanimousBased(decisionVoters);
}
我的期望是:
运行应用程序时真正发生的是,无论请求的URL是什么,始终执行自定义选民。但是,如果我删除了configure()方法的初始部分,因此未设置“ hasAuthority()”授权,则自定义选民只会在与正则表达式匹配的URL上执行。
如果使用以下类型,则会发生相同类型的不良行为:
http.authorizeRequests().anyRequest().authenticated();
在设置自定义AccessDecisionManager之前。
在进行此设置时,我显然会犯一些错误。自定义选民是否应该始终只在与“ REGEX_PATTERN_URLS_THAT_NEED_AUTHORISATION”模式匹配的网址上运行?
谢谢!
答案 0 :(得分:1)
您在AccessDecisionManager
中注册的.accessDecisionManager(...)
bean在您的 整个 春季安全应用程序中共享,因此任何时候都必须做出授权决定,则将调用相同的UnanimousBased
决策管理器,依次调用您的自定义投票者。
所以这个:
authorizeRequests()
.requestMatchers(getMatcherForAuthorities1and2Urls())
.hasAnyAuthority("AUTHORITY1", "AUTHORITY1");
将为AccessDecisionManager
调用与"matcherForAuthorities1and2Urls"
相同的REGEX_PATTERN_URLS_THAT_NEED_AUTHORISATION
:
authorizeRequests()
.regexMatchers(REGEX_PATTERN_URLS_THAT_NEED_AUTHORISATION).authenticated()
.accessDecisionManager(myAccessDecisionManager());
类似地,包括http.authorizeRequests().anyRequest().authenticated()
在内的用户将注册一个匹配每个请求的匹配器,并要求相同的AccessDecisionManager
决定访问权限。
可能的解决方案
也许一种实现所需行为的方法是通过其构造函数将REGEX_PATTERN_URLS_THAT_NEED_AUTHORISATION
传递到自定义投票器,并使用它来创建RequestMatcher
。然后,您的选民可以决定是否根据每个请求“投票”:
public int vote(Authentication authentication, FilterInvocation fi,
Collection<ConfigAttribute> attributes) {
if(!regexPatternMatcher.matches(fi.getRequest())) {
return ACCESS_ABSTAIN;
}
// ...
}