Как я могу использовать одну аутентификацию для запросов Post и другую аутентификацию для запросов GET для одного набора защищенных ресурсов?

#spring #spring-security

#spring #spring-безопасность

Вопрос:

Я пытаюсь защитить набор ресурсов (/admin /**) с помощью OAuth или базовой аутентификации. Я успешно реализовал оба из них по отдельности (2 diff. WebSecurityAdapters с @Order) или вместе (один WebSecurityAdapter). Однако мне нужно использовать либо или.

Моей текущей стратегией для этого было бы СООБЩЕНИЕ в /admin/** использует базовую аутентификацию, а для перехода к тому же URL-адресу используется OAuth. Это выполнимо? Или есть другой способ добиться этого?

Или есть способ, чтобы все запросы к /admin/** требовали OAuth, если только кто-то не аутентифицируется с помощью Basic Auth — и есть ли способ выполнить базовую аутентификацию по другому URL, который правильно заполнял бы SecurityContext, чтобы в случае выполнения базовой аутентификации посещение /admin/** также не будет OAuth?

Текущая реализация OAuth или Basic Auth (в зависимости от того, какой из них является Order(1)):

 @Configuration
@Order(2)
public class BasicAuth extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
      http.headers().frameOptions().sameOrigin().and().cors().and().csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()).and().httpBasic().and().authorizeRequests()
            .antMatchers("/**/*.{js,html,css}", "/", "/api/user", "/static/css/**/*", "/static/css/*", "/static/js/*", "/static/js/**/*").permitAll()
            .anyRequest().authenticated();
    }
}
  
 @EnableWebSecurity(debug = true)
@Configuration
@Order(1)
public class OAuth extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
         http.addFilterAfter(this.oauthConsumerContextFilter(), SwitchUserFilter.class);
         http.addFilterAfter(this.oauthConsumerProcessingFilter(), OAuthConsumerContextFilter.class);
    }

    // IMPORTANT: this must not be a Bean
    OAuthConsumerContextFilter oauthConsumerContextFilter() {
        OAuthConsumerContextFilter filter = new OAuthConsumerContextFilter();
        filter.setConsumerSupport(this.consumerSupport());
        return filter;
    }

    // IMPORTANT: this must not be a Bean
    OAuthConsumerProcessingFilter oauthConsumerProcessingFilter() {
        OAuthConsumerProcessingFilter filter = new OAuthConsumerProcessingFilter();
        filter.setProtectedResourceDetailsService(this.prds());

        LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> map = new LinkedHashMap<>();

        // one entry per oauth:url element in xml
        map.put(
                // 1st arg is equivalent of url:pattern in xml
                // 2nd arg is equivalent of url:httpMethod in xml
                new AntPathRequestMatcher("/admin/**", null),
                // arg is equivalent of url:resources in xml
                // IMPORTANT: this must match the ids in prds() and prd() below
                Collections.singletonList(new SecurityConfig("myResource")));
                map.put(
                    // 1st arg is equivalent of url:pattern in xml
                    // 2nd arg is equivalent of url:httpMethod in xml
                    new AntPathRequestMatcher("/auth/setup", null),
                    // arg is equivalent of url:resources in xml
                    // IMPORTANT: this must match the ids in prds() and prd() below
                    Collections.singletonList(new SecurityConfig("myResource")));

        filter.setObjectDefinitionSource(new DefaultFilterInvocationSecurityMetadataSource(map));

        return filter;
    }

    @Bean // optional, I re-use it elsewhere, hence the Bean
    OAuthConsumerSupport consumerSupport() {
        CoreOAuthConsumerSupport consumerSupport = new CoreOAuthConsumerSupport();
        consumerSupport.setProtectedResourceDetailsService(prds());
        return consumerSupport;
    }

    @Bean // optional, I re-use it elsewhere, hence the Bean
    ProtectedResourceDetailsService prds() {
        return (String id) -> {
            switch (id) {
                // this must match the id in prd() below
                case "myResource":
                    return prd();
            }
            throw new RuntimeException("Invalid id: "   id);
        };
    }

    ProtectedResourceDetails prd() {
        BaseProtectedResourceDetails details = new BaseProtectedResourceDetails();

        // this must be present and match the id in prds() and prd() above
        details.setId("myResource");

        details.setConsumerKey("asdf");
        details.setSharedSecret(new SharedConsumerSecretImpl("asdf"));

        details.setRequestTokenURL("<url>/oauth-request-token");
        details.setUserAuthorizationURL("<url>/oauth-authorize");
        details.setAccessTokenURL("<url>/oauth-access-token");

        // enable oauth 1.0a
        details.setUse10a(true);

        // any other service-specific settings

        return details;
    }
}
  

Ответ №1:

Вы можете определить свои адаптеры безопасности, как показано ниже:

 @EnableWebSecurity(debug = true)
@Configuration
@Order(1)
public class OAuth extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
         http.requestMatcher(new AntPathRequestMatcher("/admin/**", HttpMethod.GET.toString()));
         http.addFilterAfter(this.oauthConsumerContextFilter(), SwitchUserFilter.class);
         http.addFilterAfter(this.oauthConsumerProcessingFilter(), OAuthConsumerContextFilter.class);
}

@Configuration
@Order(2)
public class BasicAuth extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
      http.requestMatcher(new AntPathRequestMatcher("/admin/**", HttpMethod.POST.toString())).headers().frameOptions().sameOrigin().and().cors().and().csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()).and().httpBasic().and().authorizeRequests()
            .antMatchers("/**/*.{js,html,css}", "/", "/api/user", "/static/css/**/*", "/static/css/*", "/static/js/*", "/static/js/**/*").permitAll()
            .anyRequest().authenticated();
    }
}
  

Приведенная выше конфигурация должна разрешать БАЗОВУЮ аутентификацию для запросов POST и OAUTH для запросов GET.

Ответ №2:

Вы могли бы определить пользовательский сопоставитель запросов для проверки базовой аутентификации :

 public class BasicUrlAntPathRequestMatcher implements RequestMatcher {
private final String pattern;
public BasicUrlAntPathRequestMatcher(String pattern) {
 this.pattern = pattern;
}

@Override
public boolean matches(HttpServletRequest request) {
    String auth = request.getHeader(HttpHeaders.AUTHORIZATION);
    boolean hasBasicToken = (auth != null) amp;amp;  auth.startsWith("Basic");
    return !(new AntPathRequestMatcher(this.pattern).matches(request) || hasBasicToken);
}}
  

И в вашем классе конфигурации OAuth вы можете добавить эту строку в конфигурацию http

     @Override
protected void configure(HttpSecurity http) throws Exception {
    http.requestMatcher(new BasicUrlAntPathRequestMatcher("your/basic/login"));

    http.addFilterAfter(this.oauthConsumerContextFilter(), SwitchUserFilter.class);
    http.addFilterAfter(this.oauthConsumerProcessingFilter(), OAuthConsumerContextFilter.class);
}