С помощью Весенний ботинок 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?




По умолчанию 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 без тела. Это нормально для js, но при просмотре в Firefox это пустая страница, а при просмотре в Chrome отображается сообщение «Эта страница не работает». Однако легко сделать собственную замену Htp401AuthenticationEntryPoint и использовать ее. Просто внедрите AuthenticationEntryPoint и установите любой желаемый статус и сообщение.
@Planky большое спасибо за то, что указали на это! Я просто изложил возможный подход, которому могут следовать другие, основываясь на вашем комментарии :)
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 removeHttp401AuthenticationEntryPoint.
В зависимости от ваших требований вы можете использовать:
Спасибо, очень полезная ссылка из репозитория spring boot git. В ответе, который я предоставил, будущие читатели могут увидеть, как я использовал HttpStatusEntryPoint в соответствии с моими требованиями.
Просто чтобы уточнить ответ @ 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, который сообщал бы клиенту, как он может попытаться аутентифицироваться.
Вы можете настроить свою логику, переопределив класс 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\"}");
}
}
Теперь неверные запросы учетных данных возвращают 401, но пустой ответ. Кроме того, неавторизованные запросы, которые должны возвращать 403, также возвращают 401 с пустым ответом.