Добавление заголовка «Авторизация» заставляет Spring Security защищать разрешенную конечную точку - PullRequest
0 голосов
/ 28 марта 2019

Итак, у меня есть это в моем WebSecurityConfigurerAdapter

public class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                // Use this configuration for endpoints starting with 'api'
                .antMatcher("/api/**")
                // Do not secure endpoints receiving callbacks
                .authorizeRequests().antMatchers(""/api/v1/notification").permitAll()
                // Allow only users with role "ROLE_API"
                .anyRequest().hasRole(Users.UserRoles.ROLE_API.role.replace("ROLE_", ""))
                .and()
                .httpBasic()
                .and()
                // Do not create any sessions
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                // Disable csrf
                .csrf().disable();            

    }

}

, который не должен защищать /api/v1/notification.Если я вызову эту конечную точку без Authorization: Basic abcd в заголовке HTTP, запрос будет разрешен, но если я добавлю заголовок Authorization: Basic abcd, я получу 401 http код ответа.

NB: Basic abcd просто случайный, поэтому такого пользователя нет в моей базе данных

Вопрос в том, почему добавление Authorization... в заголовок http делает конечную точку снова защищенной?

1 Ответ

1 голос
/ 29 марта 2019

Хороший вопрос, это может немного сбивать с толку, поскольку это означает, что законному клиенту, только с неверным паролем, может быть отказано в доступе к странице, которую остальной мир может увидеть без учетных данных.

На самом деле,это по замыслу.Вообще говоря, система авторизации должна знать, кто пользователь, прежде чем узнает, может ли пользователь выполнять операции X, Y или Z.И даже с общедоступной конечной точкой, возможно, что конечная точка может вести себя по-другому, когда пользователь находится в контексте.Таким образом, на самом деле это отдельные системы, в которых на первом месте стоит аутентификация: если в запросе представлены учетные данные, то платформа попытается аутентифицировать пользователя и соответственно принять или отклонить запрос.

Опция

Я понимаю, что вы не спрашивали, как решить эту проблему (вы можете быть полностью удовлетворены поведением и просто любопытствовать), но одна вещь, которую вы можете сделать с BasicAuthenticationFilter, - это настроить его так, чтобы он игнорировал сбои только для этой конечной точки:

static class IgnoreFailuresBasicAuthenticationFilter extends BasicAuthenticationFilter {
    private final BasicAuthenticationFilter everythingElse;

    public IgnoreFailuresBasicAuthenticationFilter(BasicAuthenticationFilter everythingElse) {
        super(everythingElse.getAuthenticationManager());
        this.everythingElse = everythingElse;
    }

    protected void doFilterInternal(request, response, chain) {
        if ("/api/v1/notification".equals(request.getPathInfo())) {
            super.doFilterInternal(request, response, chain);
        } else {
            this.everythingElse.doFilterInternal(request, response, chain);
        }
    }
}

И затем замените фильтр в DSL:

http
    .httpBasic()
        .withObjectPostProcessor(
            new ObjectPostProcessor<BasicAuthenticationFilter>() {
                public BasicAuthenticationFilter postProcess(BasicAuthenticationFilter filter) {
                    return new IgnoreFailuresBasicAuthenticationFilter(filter);
                }
            });

Что это сделает, это позволит цепочке фильтров продолжить работу, даже если обычная аутентификация не удалась.Следствием этого будет то, что в случае сбоя аутентификации вы получите 403 вместо 401.

...