Почему вызов моего микросервиса в Java Spring Boot возвращает 403 Forbidden?

Я использую SpringBoot с Eureka Server. У меня есть пользователи microservice, одна eureka server и одна springcloud apigateway папка. Вот полный исходный код

В моем users microservice's controller у меня есть код ниже

@RestController
@RequestMapping("/users")
public class UsersController {

    @Autowired
    private Environment env;

    @Autowired
    UsersService usersService;

    @GetMapping("/status/check")
    public String status(){
        System.out.println("hereeeeeeeeeee");
        return "Working "+env.getProperty("local.server.port");
    }

    @PostMapping
    public ResponseEntity<CreateUserResponseModel> createUser(@Valid @RequestBody CreateUserRequestModel userDetails) {
        ModelMapper modelMapper = new ModelMapper();
        modelMapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);
        UserDto userDto = modelMapper.map(userDetails, UserDto.class);
        UserDto createdUser = usersService.createUser(userDto);
        CreateUserResponseModel body = modelMapper.map(createdUser, CreateUserResponseModel.class);
        return  ResponseEntity.status(HttpStatus.CREATED).body(body);
    }
    
}

Теперь конечная точка Get API возвращается в виде 403 Forbidden, конечная точка публикации работает нормально.

Ниже скриншот ошибки

Я определил класс AuthorizationHeaderFilter в apigateway, который используется для декодирования jwt, который я отправляю в конечной точке GET Api, и он правильно декодирует JWT

@Component
public class AuthorizationHeaderFilter extends AbstractGatewayFilterFactory<AuthorizationHeaderFilter.Config>{

    @Autowired
    private Environment environment;

    public AuthorizationHeaderFilter(){
        super(Config.class);
    }

    public static class Config{

    }

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange,chain)->{
            ServerHttpRequest request = exchange.getRequest();
            if (!request.getHeaders().containsKey(HttpHeaders.AUTHORIZATION)){
                return onError(exchange,"No authorization header",HttpStatus.UNAUTHORIZED);
            }
            String authorizationHeader = request.getHeaders().get(HttpHeaders.AUTHORIZATION).get(0);
            String jwt = authorizationHeader.replace("Bearer ", ""); //Make sure you add space
            if (!isJwtValid(jwt)){
                return onError(exchange, "Jwt token is invalid",HttpStatus.UNAUTHORIZED);
            }
            return chain.filter(exchange);
        };
    }

    private Mono<Void> onError(ServerWebExchange exchange,String err,HttpStatus httpStatus){
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(httpStatus);
        return response.setComplete();
    }

    private boolean isJwtValid(String jwt){
        System.out.println("1");
        boolean isValid = false;
        String subject = null;
        String tokenSecret = environment.getProperty("token.secret");
        System.out.println("2 "+tokenSecret);
        SecretKey secretKey = Keys.hmacShaKeyFor(tokenSecret.getBytes());

        JwtParser jwtParser = Jwts.parser().verifyWith(secretKey).build();
        try{
            // Jwt<Header,Claims> parsedToken = jwtParser.parse(jwt);
            subject = jwtParser.parseSignedClaims(jwt).getPayload().get("userId").toString();
            System.out.println("3 "+subject);
        } catch(Exception ex){
            isValid = false;
            System.out.println("4 "+ex.getLocalizedMessage());
        }

        if (subject == null || subject.isEmpty()){
            isValid = false;
        } else {
            isValid = true;
        }
        System.out.println("5 ");
        return isValid;
    }

  
}

Вот application.properties моего apigateway

spring.application.name=api-gateway
server.port=8082
eureka.client.service-url.defaultZone=http://localhost:8010/eureka

spring.cloud.gateway.routes[0].id=users-status-check
spring.cloud.gateway.routes[0].uri=lb://users-ws
spring.cloud.gateway.routes[0].predicates[0]=Path=/users-ws/users/status/check
spring.cloud.gateway.routes[0].predicates[1]=Method=GET
spring.cloud.gateway.routes[0].predicates[2]=Header=Authorization, Bearer (.*)
spring.cloud.gateway.routes[0].filters[0]=RemoveRequestHeader=Cookie
spring.cloud.gateway.routes[0].filters[1]=RewritePath=/users-ws/(?<segment>.*), /$\{segment}
spring.cloud.gateway.routes[0].filters[2]=AuthorizationHeaderFilter

spring.cloud.gateway.routes[1].id=users-ws
spring.cloud.gateway.routes[1].uri=lb://users-ws
spring.cloud.gateway.routes[1].predicates[0]=Path=/users-ws/users
spring.cloud.gateway.routes[1].predicates[1]=Method=POST
spring.cloud.gateway.routes[1].filters[0]=RemoveRequestHeader=Cookie
spring.cloud.gateway.routes[1].filters[1]=RewritePath=/users-ws/(?<segment>.*), /$\{segment}

spring.cloud.gateway.routes[2].id=users-ws-h2-console
spring.cloud.gateway.routes[2].uri=lb://users-ws
spring.cloud.gateway.routes[2].predicates[0]=Path=/users-ws/h2-console
spring.cloud.gateway.routes[2].predicates[1]=Method=GET
spring.cloud.gateway.routes[2].filters[0]=RemoveRequestHeader=Cookie
spring.cloud.gateway.routes[2].filters[1]=RewritePath=/users-ws/(?<segment>.*), /$\{segment}

spring.cloud.gateway.routes[3].id=users-ws-login
spring.cloud.gateway.routes[3].uri=lb://users-ws
spring.cloud.gateway.routes[3].predicates[0]=Path=/users-ws/users/login
spring.cloud.gateway.routes[3].predicates[1]=Method=POST
spring.cloud.gateway.routes[3].filters[0]=RemoveRequestHeader=Cookie
spring.cloud.gateway.routes[3].filters[1]=RewritePath=/users-ws/(?<segment>.*), /$\{segment}

spring.cloud.gateway.routes[4].id=users-ws-get-update-delete
spring.cloud.gateway.routes[4].uri=lb://users-ws
spring.cloud.gateway.routes[4].predicates[0]=Path=/users-ws/users/**
spring.cloud.gateway.routes[4].predicates[1]=Method=GET,PUT,DELETE
spring.cloud.gateway.routes[4].predicates[2]=Header=Authorization, Bearer (.*)
spring.cloud.gateway.routes[4].filters[0]=RemoveRequestHeader=Cookie
spring.cloud.gateway.routes[4].filters[1]=AuthorizationHeaderFilter
spring.cloud.gateway.routes[4].filters[2]=RewritePath=/users-ws/(?<segment>.*), /$\{segment}

token.secret=1aBcD3eF4gH5iJ6kL7mN8oP9qRsTuVwXyZ0A1bCdEfG2hI3jK4lM5nO6pQ7rStU8vW9xYz

На снимке экрана почтальона вы устанавливаете авторизацию вручную на вкладке «Заголовки». Просто для проверки работоспособности, установлено ли что-нибудь на вкладке «Авторизация»?

wxker 19.05.2024 05:50

@wxker это моя вкладка авторизации firebasestorage.googleapis.com/v0/b/myproject-6952a.appspot.‌​com/…

BraveEvidence 19.05.2024 06:10

Можете ли вы включить журналы безопасности Spring в микросервисах ваших пользователей, добавив в свой application.properties (или аналогичный) logging.logger.org.springframework.security=DEBUG. Вы должны увидеть, откуда взялся код 403.

silver_mx 19.05.2024 19:27

@silver_mx logging.logger.org.springframework.security=DEBUG не является допустимым свойством

BraveEvidence 20.05.2024 08:27

См. baeldung.com/spring-security-enable-logging . Да, я неправильно указал объект недвижимости, извините.

silver_mx 20.05.2024 10:34

@silver_mx Я получаю эти журналы o.s.security.web.FilterChainProxy: защита GET /users/status/check o.s.s.w.a.AnonymousAuthenticationFilter: установите для SecurityContextHolder анонимный SecurityContext o.s.s.w.a.Http403ForbiddenEntryPoint: вызывается точка входа с предварительной аутентификацией. Отказ в доступе o.s.security.web.FilterChainProxy: защита GET/error o.s.s.w.a.AnonymousAuthenticationFilter: установите SecurityContextHolder в анонимный SecurityContext o.s.s.w.a.Http403ForbiddenEntryPoint: вызывается точка входа с предварительной аутентификацией. Отказ в доступе

BraveEvidence 20.05.2024 13:58

Я думаю, что в вашей службе пользователей есть какая-то конфигурация безопасности, но ваша ссылка на исходный код не работает. Проблема, вероятно, заключается в том, как настроена безопасность Spring. Можете ли вы исправить ссылку, чтобы увидеть полный исходный код?

silver_mx 20.05.2024 17:33

@silver_mx Можете ли вы проверить эту ссылку github.com/BraveEvidence/SpringBottMicorServiceTry для получения исходного кода

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

Ответы 3

При добавлении получается = MediaType.TEXT_PLAIN_VALUE.

@GetMapping(path = "/status/check", produces = MediaType.TEXT_PLAIN_VALUE)
public String status()
{
    System.out.println("hereeeeeeeeeee");
    return "Working";
}

не работает та же проблема. Кроме того, URL-адрес, по которому вы нажимаете, неправильный. Это должен быть localhost:8082/users-ws/users/status/check и для этого требуется токен носителя, чтобы вы не могли использовать его из браузера, поскольку я добавил AuthorisationFilter к этой конечной точке.

BraveEvidence 19.05.2024 08:52

В WebSecurity ваш первый requestMatchers проверяет безопасность только для /users и /h2-console/**, поэтому ваша конечная точка /users/status/checks никогда не будет авторизована каким-либо фильтром и всегда будет возвращать 403.

Ваша конечная точка POST /users всегда разрешена, поэтому она у вас работает.

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

Я обновил файл WebSecurity.java в вашей службе пользователей и изменил строку:

.authorizeHttpRequests(auth -> auth.requestMatchers(HttpMethod.POST, "/users")
.permitAll()

к

.authorizeHttpRequests(auth -> auth.requestMatchers("/users/**")
.permitAll()

Таким образом, Spring Security разрешает не только запросы POST, но и запросы GET, а также вы можете вызывать пути под /users. После этого я получил правильный ответ.

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