Проблема с авторизацией в весенней конфигурации безопасности API-шлюза

1
9

Я настроил свой шлюз API, чтобы проверить, разрешен ли пользователю доступ к некоторым маршрутам, вот конфигурация, но я получаю отказ в доступе, хотя у пользователя есть правильные роли вот пример того, что я получаю:

2024-08-20T13:08:38.091+01:00 DEBUG 27199 --- [api-gateway] [ctor-http-nio-3] o.s.w.s.adapter. HttpWebHandlerAdapter: [f2b2d9a7-4] HTTP POST "/api/course" токен: eyJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJST0xFX1VTRVIiLCJST0xFX0FETUlOIl0sInN1YiI6ImFkbWluLmF5YUBleGFtcGxlLmNvbSIsImlhdCI6MTcyNDE1NTUwOSwiZXhwIjoxNzI0M TU2OTQ5fQ.1WVtd-2pi--W8mKxPWBBjLApEUo0YLl4xoz2AjYUNFY Утверждения: {[email защищен], exp=2024-08-20T12:29 :09Z, iat=2024-08-20T12:05:09Z, roles=[ROLE_USER, ROLE_ADMIN]} Роль из токена: ROLE_USER Роль из токена: ROLE_ADMIN

у пользователя есть роль ADMIN, но когда я пытаюсь создать курс, мне отказывают в доступе: 2024-08-20T13:08:38.094+01:00 DEBUG 27199 --- [api-gateway] [параллельный-4] o.s.w.s.s.DefaultWebSessionManager: создан новый веб-сеанс. 2024-08-20T13:08:38.094+01:00 DEBUG 27199 --- [api-gateway] [parallel-4] o.s.s.w.s.u.m.OrServerWebExchangeMatcher: попытка сопоставления с использованием PathMatcherServerWebExchangeMatcher{pattern='/logout', Method=POST} 2024-08-20T13:08:38.094+01:00 DEBUG 27199 --- [api-шлюз] [параллельный-4] athPatternParserServerWebExchangeMatcher: запрос "POST/api/course" не соответствует "POST/logout" 2024-08-20T13:08:38.094+01:00 DEBUG 27199 --- [api-gateway] [параллельный-4] o.s.s.w.s.u.m.OrServerWebExchangeMatcher: совпадений не найдено 2024-08-20T13:08:38.094+01:00 DEBUG 27199 --- [api-gateway] [parallel-4] o.s.s.w.s.u.m.OrServerWebExchangeMatcher: попытка сопоставления с использованием PathMatcherServerWebExchangeMatcher{pattern='/api/auth/', метод = ноль} 2024-08-20T13:08:38.094+01:00 DEBUG 27199 --- [api-gateway] [parallel-4] athPatternParserServerWebExchangeMatcher: запрос "POST /api/course" не соответствует "null /api/auth/< /сильный>' 2024-08-20T13:08:38.094+01:00 DEBUG 27199 --- [api-gateway] [параллельный-4] o.s.s.w.s.u.m.OrServerWebExchangeMatcher: совпадений не найдено 2024-08-20T13:08:38.094+01:00 DEBUG 27199 --- [api-gateway] [parallel-4] o.s.s.w.s.u.m.OrServerWebExchangeMatcher: попытка сопоставления с использованием PathMatcherServerWebExchangeMatcher{pattern='/eureka/', метод = нулевой} 2024-08-20T13:08:38.094+01:00 DEBUG 27199 --- [api-gateway] [parallel-4] athPatternParserServerWebExchangeMatcher: запрос "POST /api/course" не соответствует "null /eureka/' 2024-08-20T13:08:38.094+01:00 DEBUG 27199 --- [api-gateway] [параллельный-4] o.s.s.w.s.u.m.OrServerWebExchangeMatcher: совпадений не найдено 2024-08-20T13:08:38.094+01:00 DEBUG 27199 --- [api-gateway] [параллельный-4] o.s.s.w.s.u.m.OrServerWebExchangeMatcher: попытка сопоставления с использованием PathMatcherServerWebExchangeMatcher{pattern='/api/user/', метод = ноль} 2024-08-20T13:08:38.094+01:00 DEBUG 27199 --- [api-gateway] [parallel-4] athPatternParserServerWebExchangeMatcher: запрос "POST /api/course" не соответствует "null /api/user/< /сильный>' 2024-08-20T13:08:38.094+01:00 DEBUG 27199 --- [api-gateway] [параллельный-4] o.s.s.w.s.u.m.OrServerWebExchangeMatcher: совпадений не найдено 2024-08-20T13:08:38.094+01:00 DEBUG 27199 --- [api-gateway] [parallel-4] o.s.s.w.s.u.m.OrServerWebExchangeMatcher: попытка сопоставления с использованием PathMatcherServerWebExchangeMatcher{pattern='/POST', метод = null} 2024-08-20T13:08:38.094+01:00 DEBUG 27199 --- [api-шлюз] [параллельный-4] athPatternParserServerWebExchangeMatcher: запрос "POST/api/course" не соответствует "null/POST" 2024-08-20T13:08:38.094+01:00 DEBUG 27199 --- [api-gateway] [parallel-4] o.s.s.w.s.u.m.OrServerWebExchangeMatcher: попытка сопоставления с использованием PathMatcherServerWebExchangeMatcher{pattern='/api/course', Method=null} 2024-08-20T13:08:38.094+01:00 DEBUG 27199 --- [api-gateway] [parallel-4] athPatternParserServerWebExchangeMatcher: проверка соответствия запроса: '/api/course'; против '/api/course' 2024-08-20T13:08:38.094+01:00 DEBUG 27199 --- [api-gateway] [параллельный-4] o.s.s.w.s.u.m.OrServerWebExchangeMatcher: соответствует 2024-08-20T13:08:38.094+01:00 DEBUG 27199 --- [api-gateway] [parallel-4] a.DelegatingReactiveAuthorizationManager: проверка авторизации в "/api/course" с использованием org.springframework.security.authorization. AuthorityReactiveAuthorizationManager@31960a5b 2024-08-20T13:08:38.095+01:00 DEBUG 27199 --- [api-gateway] [параллельный-4] o.s.s.w.s.a.AuthorizationWebFilter: Ошибка авторизации: доступ запрещен 2024-08-20T13:08:38.095+01:00 DEBUG 27199 --- [api-gateway] [параллельный-4] o.s.w.s.adapter.HttpWebHandlerAdapter: [f2b2d9a7-4] Завершено 200 ОК

package org.example.config;

import io.jsonwebtoken.JwtException;
import jakarta.ws.rs.HttpMethod;
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.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.security.oauth2.jwt.*;
import org.springframework.security.web.server.SecurityWebFilterChain;
import reactor.core.publisher.Mono;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
import java.util.List;


@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {

    @Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}")
    private String issuerUri;
    private static final String SECRET_KEY = "5367566B59703373367639792F423F4528482B4D6251655468576D5A71347437";


    @Bean
    public SecurityWebFilterChain filterChain(ServerHttpSecurity serverHttpSecurity) {
        serverHttpSecurity
                .csrf(ServerHttpSecurity.CsrfSpec::disable)
                .authorizeExchange(exchange -> {
                    exchange
                            .pathMatchers("/api/auth/**").permitAll()
                            .pathMatchers("/eureka/**").permitAll()

                            .pathMatchers("/api/user/**").hasRole("MASTER")

                            .pathMatchers(HttpMethod.POST, "/api/course").hasAnyRole("MASTER", "ADMIN")
                            .pathMatchers(HttpMethod.PUT, "/api/course/**").hasAnyRole("MASTER", "ADMIN")
                            .pathMatchers(HttpMethod.DELETE, "/api/course/**").hasRole("MASTER")
                            .pathMatchers(HttpMethod.GET, "/api/course/**").hasAnyRole("MASTER", "ADMIN", "USER")

                            .anyExchange().authenticated();
                })
                .oauth2ResourceServer(oauth2 -> oauth2.jwt(jwt -> jwt.jwtDecoder(jwtDecoder())))
                .exceptionHandling((exception)->exception.accessDeniedHandler(((exchange, denied) -> {
                    // Log the denied access details
                    ReactiveSecurityContextHolder.getContext()
                            .doOnNext(securityContext -> {
                                Authentication authentication = securityContext.getAuthentication();
                                if (authentication != null) {
                                    System.out.println("Authenticated user: " + authentication.getName());
                                    System.out.println("Authorities: " + authentication.getAuthorities());
                                } else {
                                    System.out.println("No authentication found in context");
                                }
                            })
                            .subscribe();
                    System.out.println("Access Denied for request path: " + exchange.getRequest().getPath());
                    return exchange.getResponse().setComplete();

                })));

        return serverHttpSecurity.build();
    }

    @Bean
    public ReactiveJwtDecoder jwtDecoder() {

        // Decode the Base64-encoded SECRET_KEY
        byte[] keyBytes = Base64.getDecoder().decode(SECRET_KEY);
        SecretKey secretKey = new SecretKeySpec(keyBytes, "HmacSHA256");

        // Use the secret key to create a NimbusReactiveJwtDecoder
        NimbusReactiveJwtDecoder jwtDecoder = NimbusReactiveJwtDecoder.withSecretKey(secretKey).build();

        return token -> {
            System.out.println("token: " + token);
            return jwtDecoder.decode(token)
                    .doOnNext(jwt -> {
                        System.out.println("Claims: " + jwt.getClaims());
                        List<String> roles = jwt.getClaimAsStringList("roles");
                        if (roles != null) {
                            roles.forEach(role -> System.out.println("Role from token: " + role));
                        }
                    });
        };
    }

}

Клавдия
Вопрос задан1 июля 2024 г.

1 Ответ

Ваш ответ

Загрузить файл.