erondem
erondem

Reputation: 592

Can I use Spring Cloud Gateway for role based authorization?

I have several microservices in my architecture. I want to implement an API Gateway to route request to services. To achieve that, I implement spring-cloud-gateway and this is my application.yml

server:
  port: 9090
spring:
  application:
  name: "API-GATEWAY"
  cloud:
   gateway:
    routes:
      - id: task-service
        uri: 'http://localhost:8083'
        predicates:
          - Path=/task/**

So far everything works as expected. a request localhost:9090/task/123 is to localhost:8083/task/123. Here comes to second part.

I want some users access to only some endpoints. In my JWT token, I have role field.

  {
      "accountName": "erdem.ontas",
      "surname": "Öntaş",
      "roles": [
        "ADMIN",
        "USER"
      ],
}

I don't want specify authorization in every service separately, is there any way to specify role based access in spring-cloud-gateway? For example I want USER role to be able to access to GET http://localhost:9090/task/ but not to GET http://localhost:9090/dashboard/

Upvotes: 3

Views: 8391

Answers (1)

Babl
Babl

Reputation: 7646

If you do not want and need to create full OAuth 2 Server/Client infrastructure and want to keep it simple just create a custom GatewayFilter in which just check if the JWT token extracted from the header has the preconfigured roles. So start with a simple GatewayFilter

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

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

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            var request = exchange.getRequest();
            // JWTUtil can extract the token from the request, parse it and verify if the given role is available
            if(!JWTUtil.hasRole(request, config.getRole())){
                // seems we miss the auth token
                var response = exchange.getResponse();
                response.setStatusCode(HttpStatus.UNAUTHORIZED);
                return response.setComplete();
            }
            return chain.filter(exchange);
        };
    }

    @Data
    public static class Config {
        private String role;
    }

    @Override
    public List<String> shortcutFieldOrder() {
        // we need this to use shortcuts in the application.yml
        return Arrays.asList("role");
    }
}

Here we just create a simple filter which receives the required role from the config (application.yml) and checks if the request is authorized to continue.

To use the filter just add filters into you route config.

server:
  port: 9090
spring:
  application:
  name: "API-GATEWAY"
  cloud:
    gateway:
      routes:
        - id: task-service
          uri: 'http://localhost:8083'
          filters:
            - RoleAuth=ADMIN
          predicates:
            - Path=/task/**
          

So this way the RoleAuth filter can be reused over the several routes.

Upvotes: 10

Related Questions