AccessDeniedHandler не вызывается при использовании AadResourceServerHttpSecurityConfigurer

Мое приложение представляет собой простой сервер ресурсов — я использую AadResourceServerHttpSecurityConfigurer.aadResourceServer() для проверки данного токена доступа. Конкретную документацию, которой я следовал, можно найти здесь.

Цель: возвращать пользовательское сообщение об ошибке, когда указан неверный токен (например, «123»). Не похоже, что мой accessDeniedHandler зовут. Напротив, когда я вообще не указываю JWT, он работает нормально и возвращается пользовательское сообщение об ошибке (вызывается authenticationEntryPoint).

Это код, который я использую (я изменил пример Microsoft, поскольку в нем использовались устаревшие методы):

@Autowired
private ErrorHandler errorHandler;

@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
    .csrfCustomizer -> csrfCustomizer.disable())
    .with(AadResourceServerHttpSecurityConfigurer
        .aadResourceServer(), Customizer.withDefaults())
    .authorizeHttpRequests(requests -> requests
        .requestsMatchers(antMatcher("/users/**")).permitAll()
        .requestMatchers(antMatcher(HttpMethod.GET, "/admin")).hasRole(ADMIN_ROLE)    
        .anyRequest().authenticated()
    )
    .exceptionHandling(exceptionHandlingCustomizer -> exceptionHandlingCustomizer.authenticationEntryPoint(errorHandler))
    .exceptionHandling(exceptionHandlingCustomizer -> exceptionHandlingCustomizer.accessDeniedHandler(errorHandler))
    .sessionManagement(sessionManagement -> sessionManagementCustomizer.sessionCreationPolicy(sessionCreationPolicy.STATELESS)));

    return http.build();
}

Конкретный обработчик ошибок (упрощенный):

@Configuration
public class ErrorHandler authenticationEntryPoint, AccessDeniedHandler {
    @Override
    public void commence() {
        // this is called
    }

    @Override
    public void handle() {
        // this is not called
    }
}

Напротив, эта конфигурация работает нормально, и когда я предоставляю неверный токен, но не использую AadResourceServerHttpSecurityConfigurer.aadResourceServer(), возвращается пользовательское сообщение об ошибке:

@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
    .csrfCustomizer -> csrfCustomizer.disable())
    .oauth2ResourceServer(httpSecurityOAuth2ResourceServerConfigurer -> httpSecurityOAuth2ResourceServerConfigurer
        .authenticationEntryPoint(errorHandler)
        .accessDeniedHandler(errorHandler)
    )
    .authorizeHttpRequests(requests -> requests
        .requestsMatchers(antMatcher("/users/**")).permitAll()
        .requestMatchers(antMatcher(HttpMethod.GET, "/admin")).hasRole(ADMIN_ROLE)    
        .anyRequest().authenticated()
    )
    .sessionManagement(sessionManagement -> sessionManagementCustomizer.sessionCreationPolicy(sessionCreationPolicy.STATELESS)));

    return http.build();
}

Есть ли способ использовать AadResourceServerHttpSecurityConfigurer.aadResourceServer() с обработчиками исключений authenticationEntryPoint и accessDeniedHandler?

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

Ответы 2

Из соображений безопасности вы пропустили?

@EnableWebSecurity
@EnableMethodSecurity

В вашем классе конфигурации Я нашел этот «туто» https://gpiskas.com/posts/refresh-oauth2-tokens-spring-boot-spring-cloud-azure/ и ваш, и этот используют эти аннотации.

Для части исключения вы можете использовать более глобальный обработчик исключений.

@ControllerAdvice
@ResponseBody
class CustomExceptionHandler(){

    @ExceptionHandler
    @ResponseStatus(HttpStatus.UNPROCESSABLE_ENTITY)
    CustomErrorObj customExceptionHandling(e: CustomException) {
        return new CustomErrorObj(e.class.getName()+": "+e.getMessage())
    }

}

Спасибо за помощь. Статью, на которую вы ссылаетесь, я действительно тоже нашел, но, к сожалению, это не помогло, поскольку она все еще не вызвала мой обработчик отказа в доступе. Я попробовал ваш пример ControllerAdvice (не таким образом, а пытаясь обработать само исключение AccessDeniedException). Это не сработало — и я верю, что ваш пример отловит всевозможные исключения — я еще этого не пробовал. Мы свяжемся с вами по этому поводу как можно скорее!

Moody 16.07.2024 23:41
Ответ принят как подходящий

но я не использую AadResourceServerHttpSecurityConfigurer.aadResourceServer()

Я бы не стал использовать AadResourceServerHttpSecurityConfigurer в качестве требования.

Собственные загрузочные стартеры Microsoft обслуживаются и документируются случайным образом. Иногда требовалось некоторое время, прежде чем они публиковали версии, совместимые с новыми версиями Spring Security, и не всегда совсем ясно, с какими версиями совместима страница документации / стартовая библиотека. По этой причине я предпочитаю использовать только официальные стартеры Spring Boot (spring-boot-stater-client или spring-boot-stater-resource-server), опционально с моим дополнительным стартером, который совместим с любым сервером авторизации OIDC (AAD, а также Keycloak, Auth0, Amazon Cognito, ...)

Итак, ваша вторая конференция — лучшая отправная точка. «Мой» стартовый загрузчик может помочь заменить конфигурацию безопасности Java только свойствами приложения (и реализовать довольно сложные функции, такие как защита CSRF на основе файлов cookie, сопоставление полномочий, мультитенантность, изменение статусов перенаправления потока кода авторизации и многое другое).

P.S.

401 — это то, что сервер ресурсов должен вернуть в случае отсутствия или недействительности токена (истек срок действия, неправильный эмитент или аудитория и т. д.). Поэтому убедитесь, что вы не меняете ничего, кроме сообщения об ошибке.

Большое спасибо за подробный ответ! Я согласен с 401 — я просто хочу настроить тело ответа, что мне сложно сделать в данный момент, используя первую конфигурацию. Есть идеи, как я могу это сделать, используя первый пример, если это вообще возможно?

Moody 16.07.2024 23:42

Кроме того, вы правы, поскольку я вижу, что внутренне AadResourceServerHttpSecurityConfigurer использует oauth2ResourceServer().jwt(). Полагаю, меня больше всего беспокоит «магия», стоящая за всем этим. В моей второй конфигурации я совершенно понятия не имею, как этот токен jwt проверяется на честность. Я добавил ваш стартер в закладки. Откуда вы узнали, что стартеры случайным образом обслуживаются и документируются?! Честно говоря, ваш комментарий об использовании второй конфигурации в качестве отправной точки меня немного облегчил!

Moody 16.07.2024 23:42

Именно различные проблемы, с которыми я столкнулся при использовании различных проприетарных стартеров (все в конечном итоге делали одно и то же: настройку Spring Security для OpenID), побудили меня написать свой собственный.

ch4mp 16.07.2024 23:59

У меня тот же репозиторий, что и у стартера, я поддерживаю туториалы, некоторые из которых посвящены самостоятельной настройке Spring Security (без моего стартера)

ch4mp 17.07.2024 00:11

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