自定义AccessDecisionManager意外运行

时间:2019-06-17 21:23:34

标签: spring spring-boot spring-security authorization

我有一个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);
    }

我的期望是:

  1. 某些URL仅由具有权限1的用户访问,某些仅由 具有authority2和其他URL的用户可能会被用户访问 与任何一个权威。这是在 configure()方法。
  2. 在授权基础上,由正则表达式定义的某些特定URL 根据授权,还将执行自定义AccessDecisionManager, 其中包括自定义选民。

运行应用程序时真正发生的是,无论请求的URL是什么,始终执行自定义选民。但是,如果我删除了configure()方法的初始部分,因此未设置“ hasAuthority()”授权,则自定义选民只会在与正则表达式匹配的URL上执行。

如果使用以下类型,则会发生相同类型的不良行为:

http.authorizeRequests().anyRequest().authenticated();

在设置自定义AccessDecisionManager之前。

在进行此设置时,我显然会犯一些错误。自定义选民是否应该始终只在与“ REGEX_PATTERN_URLS_THAT_NEED_AUTHORISATION”模式匹配的网址上运行?

谢谢!

1 个答案:

答案 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;
    }
    // ...
}