2
respostas

[Projeto] Microsserviços - Filtro de autenticação no Gateway

Olá pessoal,

Eu quero configurar um filtro de autenticação no meu gateway, onde eu irei mapear as rotas seguras e aplicarei este filtro a elas; ele irá recuperar o token de autorização e delegar ao serviço auth-ms (serviço que tem a única responsabilidade de validar tokens) para ser validado. O meu problema é que eu não estou conseguindo alcançar o comportamento esperado do meu filtro. A ideia seria quebrar o fluxo de execução caso o request não cumpra algumas regras como: possuir um header Authorization; o valor do token ter "Bearer " na String e etc. De acordo com a regra ele deve lançar uma exception com uma mensagem diferente.

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

    public TestFilter() {
        super(Config.class);
    }
    
    @Override
    public GatewayFilter apply(Config config) {
        System.out.println("pre lambda log");
        
        return (exchange, chain) -> {
            System.out.println("123 testing");
            return chain.filter(exchange);
        };
    }
    
    public static class Config {
    }
}

O mapeamento das rotas está sendo feito através do application.yml:


server:
  port: 9092

logging:
    pattern:
      console: "%msg%n"
      
      
spring:

  application:
    name: gateway

  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
          lower-case-service-id: true
      routes:
      - id: account-auth-route
        uri: lb://auth-ms
        predicates:
          Path=/auth/**
        filters:
          - TestFilter


eureka:
  instance:
    instance-id: "${spring.application.name}:${random.int}"
  client:
    serviceUrl:
      defaultZone: http://localhost:9091/eureka

Parece que ele não está sendo executado, mesmo com o log "pre lambda log" sendo impresso, qualquer coisa que é feita dentro da expressão não reflete na aplicação. Qualquer log que é lançado, exceptions e até alterações no request do client não resultam em nada, os logs não são impressos, as exceptions não quebram nenhum fluxo e as alterações no request do cliente não acontecem.

  • O gateway é acessado em localhost:9092, um dos vários serviços pode ser acessado em localhost:9094/auth/test . Para acessar esse endpoint através do gateway seria localhost:9092/auth-ms/auth/test

Para fins de teste implementei um GlobalFilter e injetei. Funcionou como esperado, mas não é adequado para a aplicação.

O básico do projeto, apenas com o EurekaServer, Gateway e um dos serviços estão em https://github.com/mateuspontess/ms-app.git

Não consegui descobrir aonde estou errando...

2 respostas

Olá Mateus, tudo bem?

Com forme o que analisei, parece que o filtro personalizado TestFilter não está interceptando e modificando as requisições como esperado. Uma possível causa para isso pode ser a maneira como o filtro está sendo aplicado ou a lógica interna do filtro que não está corretamente configurada para manipular a requisição e a resposta.

Vamos tentar ajustar o seu filtro para que ele possa interceptar a requisição, verificar o token e, se necessário, modificar o fluxo (por exemplo, lançando uma exceção quando o token não é válido). Aqui está um exemplo de como você pode modificar o seu filtro para incluir essas verificações:

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

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

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            System.out.println("Dentro do filtro");

            // Recuperar o header Authorization
            String authHeader = exchange.getRequest().getHeaders().getFirst("Authorization");

            if (authHeader == null || !authHeader.startsWith("Bearer ")) {
                System.out.println("Token inválido ou ausente");
                throw new RuntimeException("Token inválido ou ausente");
            } else {
                // Aqui você pode adicionar a lógica para validar o token com o serviço auth-ms
                System.out.println("Token recebido: " + authHeader);
            }

            return chain.filter(exchange);
        };
    }

    public static class Config {
        // Configurações do filtro, se necessário
    }
}

Neste código, o filtro verifica se o header Authorization está presente e se começa com "Bearer ". Se não estiver conforme esperado, ele lança uma exceção. Você pode substituir a exceção por qualquer outra lógica de manipulação de erro que seja mais adequada para o seu contexto.

Além disso, certifique-se de que o filtro está sendo corretamente registrado e aplicado às rotas desejadas no seu arquivo application.yml. Como você já tem uma configuração que aplica o TestFilter à rota /auth/**, essa parte parece estar correta.

Todavia, vale ressaltar que como não tenho acesso ao cenário completo do projeto, outros testes terão de ser feitos a fim de obter o resultado esperado, mas espero que esta resposta seja um bom ponto de partida para a resolução do seu problema.

Bons estudos!

Caso este post tenha lhe ajudado, por favor, marcar como solucionado ✓.

Oi Armano,

Não é exatamente esse o problema, o problema é que a lógica dentro dessa expressão lambda não está rodando. Esse código que você implementou dentro da interface funcional não está rodando, e o problema em si não é o seu código mas sim o método da interface funcional que não está sendo executado pelo Spring.

Se eu crio um log antes da expressão lambda, um dentro da empressão e um após a expressão lambda, são impressos somente os logs que estão fora da empressão. Isso não é só sobre log, qualquer código que coloque dentro dessa expressão lambda parece não rodar. Eu já fiz operações de manipulação do request do cliente que quando chegaram no serviço destino não haviam sido feitas; assim como também já lancei exceptions que não quebram nenhum fluxo e não são capturadas por nenhum recurso do Spring, ou seja, nunca foram lançadas.

É isso que não estou entendendo, o filtro criado por essa interface funcional parece estar sendo criado, mas não está rodando quando acesso a rota mapeada.