Пользовательский валидатор Spring Security 6 OAuth2

У меня есть java-приложение на spring-boot 3.0.5, которое настроено как сервер ресурсов следующим образом:

Зависимости Maven:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
    </dependency>

Конфигурация безопасности:

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.oauth2.core.DelegatingOAuth2TokenValidator;
import org.springframework.security.oauth2.core.OAuth2TokenValidator;
import org.springframework.security.oauth2.jwt.*;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class SecurityConfiguration {
    
    @Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}")
    private String issuerUri;
    
    
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.cors().disable()
                .csrf().disable()
                .authorizeHttpRequests()
                .requestMatchers("/actuator/**").permitAll()
                .anyRequest().authenticated()
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .oauth2ResourceServer()
                .jwt();

        return http.build();
    }
    
    @Bean
    public JwtDecoder jwtDecoder() {
        NimbusJwtDecoder jwtDecoder = JwtDecoders.fromIssuerLocation(issuerUri);

        OAuth2TokenValidator<Jwt> withIssuer = JwtValidators.createDefaultWithIssuer(issuerUri);
        OAuth2TokenValidator<Jwt> withOperation = new OperationClaimValidator();

        jwtDecoder.setJwtValidator(
                new DelegatingOAuth2TokenValidator<>(withIssuer, withOperation)
        );

        return jwtDecoder;
    }
}

Как видите, я определил JwtDecoder bean-компонент для добавления пользовательского валидатора OperationClaimValidator для JWT, потому что я хочу проверить свое пользовательское утверждение jwt operation:

import org.springframework.security.oauth2.core.OAuth2Error;
import org.springframework.security.oauth2.core.OAuth2TokenValidator;
import org.springframework.security.oauth2.core.OAuth2TokenValidatorResult;
import org.springframework.security.oauth2.jwt.Jwt;

public class OperationClaimValidator implements OAuth2TokenValidator<Jwt> {

    private static final String CLAIM_OPERATION = "operation";
    
    
    @Override
    public OAuth2TokenValidatorResult validate(Jwt jwt) {
        if (jwt.getClaimAsString(CLAIM_OPERATION).equals("Value-from-HttpServletRequest")) { // problem here
            return OAuth2TokenValidatorResult.success();
        } else {
            return OAuth2TokenValidatorResult.failure(
                    new OAuth2Error("invalid_token", "The required operation is GET", null)
            );
        }
    }
}

Проблема в том, что я хочу сравнить значение из утверждения operation со значением из HttpServletRequest#getMethod, но я не могу понять, как я могу получить доступ к HttpServletRequest из реализации OAuth2TokenValidator.

Я могу подтвердить это утверждение другим способом, используя OncePerRequestFilter:

@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    private static final String CLAIM_OPERATION = "operation";

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {

        String requestMethod = request.getMethod();
        String operationClaimValue = getOperationClaimValue(request);

        if (!requestMethod.equals(operationClaimValue)) {
            response.sendError(HttpStatus.UNAUTHORIZED.value(),
                    "Operation claim in token does not match with http method used in request");
        } else {
            filterChain.doFilter(request, response);
        }
    }

    private String getOperationClaimValue(HttpServletRequest request) {
        Principal principal = request.getUserPrincipal();
        Jwt token = ((JwtAuthenticationToken) principal).getToken();
        return token.getClaimAsString(CLAIM_OPERATION);
    }
}

, но я хотел бы добиться его реализации OAuth2TokenValidator. Есть идеи? Заранее спасибо.

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

Ответы 1

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

Вы можете получить статический доступ к ServletRequest следующим образом:

public static Optional<HttpServletRequest> getRequest() {
    RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
    if (requestAttributes instanceof ServletRequestAttributes attr) {
        return Optional.ofNullable(attr.getRequest());
    }
    return Optional.empty();
}

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