401 вместо 403 с Spring Boot 2

С помощью Весенний ботинок 1.5.6.RELEASE я смог отправить код состояния HTTP 401 вместо 403, как описано в Как разрешить несанкционированный ответ безопасности Spring (код http 401) при запросе uri без аутентификации, выполнив следующие действия:

public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //...
        http.exceptionHandling()
                .authenticationEntryPoint(new Http401AuthenticationEntryPoint("myHeader"));
        //...
    }
}

используя класс org.springframework.boot.autoconfigure.security.Http401AuthenticationEntryPoint.

Я только что обновился до Spring Boot 2.0.0.RELEASE и обнаружил, что такого класса больше нет (по крайней мере, в этом пакете).

Вопросов:

  • Существует ли этот класс (Http401AuthenticationEntryPoint) в Spring Boot?

  • Если нет, что может быть хорошей альтернативой для сохранения того же поведения в существующем проекте, чтобы сохранить согласованность с другими реализациями, которые зависят от этого кода состояния (401) вместо 403?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
15
0
9 472
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Ответ принят как подходящий

Берегись

По умолчанию Spring Boot 2 вернет 401, когда spring-boot-starter-security добавлен в качестве зависимости и выполняется неавторизованный запрос.

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

Исходный пост

Класс org.springframework.boot.autoconfigure.security.Http401AuthenticationEntryPoint был удален в пользу org.springframework.security.web.authentication.HttpStatusEntryPoint.

В моем случае код будет таким:

public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //...
        http.exceptionHandling()
            .authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED));
        //...
    }
}

Бонус

Если вам нужно вернуть некоторую информацию в теле ответа или каким-то образом настроить ответ, вы можете сделать что-то вроде этого:

1- Расширить AuthenticationEntryPoint

public class MyEntryPoint implements AuthenticationEntryPoint {
    private final HttpStatus httpStatus;
    private final Object responseBody;

    public MyEntryPoint(HttpStatus httpStatus, Object responseBody) {
        Assert.notNull(httpStatus, "httpStatus cannot be null");
        Assert.notNull(responseBody, "responseBody cannot be null");
        this.httpStatus = httpStatus;
        this.responseBody = responseBody;
    }

    @Override
    public final void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
        response.setStatus(httpStatus.value());

        try (PrintWriter writer = response.getWriter()) {
            writer.print(new ObjectMapper().writeValueAsString(responseBody));
        }
    }
}

2- Предоставьте экземпляр MyEntryPoint для конфигурации безопасности

public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // customize your response body as needed
        Map<String, String> responseBody = new HashMap<>();
        responseBody.put("error", "unauthorized");

        //...
        http.exceptionHandling()
            .authenticationEntryPoint(new MyEntryPoint(HttpStatus.UNAUTHORIZED, responseBody));
        //...
    }
}

Теперь неверные запросы учетных данных возвращают 401, но пустой ответ. Кроме того, неавторизованные запросы, которые должны возвращать 403, также возвращают 401 с пустым ответом.

Nelio Alves 26.03.2018 19:49

Это возвращает 401 без тела. Это нормально для js, но при просмотре в Firefox это пустая страница, а при просмотре в Chrome отображается сообщение «Эта страница не работает». Однако легко сделать собственную замену Htp401AuthenticationEntryPoint и использовать ее. Просто внедрите AuthenticationEntryPoint и установите любой желаемый статус и сообщение.

Planky 30.12.2019 23:20

@Planky большое спасибо за то, что указали на это! Я просто изложил возможный подход, которому могут следовать другие, основываясь на вашем комментарии :)

lealceldeiro 10.04.2020 11:31

Http401AuthenticationEntryPoint был удален.

См. Репозиторий Spring Boot на Github> Проблема # 10715 (удаление Http401AuthenticationEntryPoint):

Remove Http401AuthenticationEntryPoint

rwinch commented on 20 Oct 2017
As far as I can tell it is not being used in the Spring Boot code base, so it might be good to remove Http401AuthenticationEntryPoint.

В зависимости от ваших требований вы можете использовать:

Спасибо, очень полезная ссылка из репозитория spring boot git. В ответе, который я предоставил, будущие читатели могут увидеть, как я использовал HttpStatusEntryPoint в соответствии с моими требованиями.

lealceldeiro 17.10.2018 16:59

Просто чтобы уточнить ответ @ lealceldeiro:

До Spring Boot 2 мой класс конфигурации Securiy выглядел так:

@Configuration
public class MyConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public Http401AuthenticationEntryPoint securityException401EntryPoint() {
      return new Http401AuthenticationEntryPoint("Bearer realm=\"webrealm\"");
    }

    @Autowired
    private Http401AuthenticationEntryPoint authEntrypoint;

    @Override
    protected void configure(HttpSecurity http) throws Exception {

      // some http configuration ...

      // Spring Boot 1.5.x style
      http.exceptionHandling().authenticationEntryPoint(authEntrypoint);
    }
//...
}

А теперь в Spring Boot 2 это выглядит так:

@Configuration
public class MyConfig extends WebSecurityConfigurerAdapter {

    //Bean configuration for Http401AuthenticationEntryPoint can be removed

    //Autowiring also removed

    @Override
    protected void configure(HttpSecurity http) throws Exception {

      // some http configuration ...

      // Spring Boot 2 style
      http.exceptionHandling().authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED));
    }
//...
}

См. Также этот комментарий в Репозиторий Spring Boot на Github> PR Удалить Http401AuthenticationEntryPoint.

Решение выглядит красивым и чистым, но в нем отсутствует обязательный заголовок WWW-Authenticate, который сообщал бы клиенту, как он может попытаться аутентифицироваться.

dube 02.12.2020 09:01

Вы можете настроить свою логику, переопределив класс AuthenticationEntryPoint. это должно работать:

@Component public class AuthEntryPointException implements AuthenticationEntryPoint, Serializable {

    private static final long serialVersionUID = -8970718410437077606L;

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response,
        AuthenticationException authException) throws IOException {
        response.setStatus(HttpStatus.SC_UNAUTHORIZED);
        response.setContentType("application/json");
        response.getWriter().write("{\"result\":\"UNAUTHORIZED\",\"message\":\"UNAUTHORIZED or Invalid Token\"}");
    }
}

Другие вопросы по теме