In microservices, we divide the entire business into small independent services with specific responsibilities, and each service provides its own API interface. However, in actual business, we will not expose all sub-service interfaces separately. We need a unified portal for us to carry out request forwarding, load balancing, access authentication and other operations. Earlier we used Netflix Zuul to encapsulate Gateway services, now we use Spring Cloud Gateway to handle entry requests.

Here I’ll show you how to write a gateway service, breaking it down into several parts.

Forward requests

Spring Cloud Gateway can specify routes either in code or in configuration files, which I prefer to do in configuration files. This simple configuration forwards all/API /** requests to apI-service for processing.

spring:
    cloud.gateway.routes:
- id: api-service-route
        uri: http://localhost:8080
        predicates:
        -   Path=/api/**
        filters:
        -   StripPrefix=1
Copy the code

In this case, if the visit http://localhost:8082/api/hello, gateway – service will turn the corresponding request to http://localhost:8080/hello, the actual processing API – service.

StripPrefix is the Gateway Filter provided by Spring Cloud Gateway, which provides a number of preset Filters. You can query in the Official Documentation of the Spring Cloud Gateway, use existing Filters for quick development based on your needs, or wrap your own custom Filters using the source code of these Filters.

Load balancing

Our back-end services typically need to be highly available, registering user-Service and gateway-Service into a registry (we use Consul), By spring. Cloud. Gateway. Discovery. A locator, enabled = true to enable the service discovery, with lb: / / using load balance (the load balancer). In the Spring Cloud Gateway, the LoadBalancerClientFilter is responsible for processing lb requests and getting the actual request address.

spring.cloud.gateway:
    discovery.locator.enabled: true
    routes:
- id: api-service-route
        uri: lb://api-service
        predicates:
        -   Path=/api/**
        filters:
        -   StripPrefix=1
Copy the code

The identity authentication

Our certification center is a standard OAuth2.0 authentication service based on Spring Security implementation, So we still use spring-security-OAuth2-resource-server to integrate Gateway as an OAuth2 client.

After receiving the request, the gateway-service sends an authentication request to the authentication service. After obtaining the authorization, the gateway-service can obtain the detailed information about the currently accessed user. If an unauthorized request is detected, gateway-service returns an unauthorized error to protect internal service access security.

Theoretically, authentication could also be done by customizing the Gateway Filter, but we want to use as much of what Spring-Security provides as possible, since it’s a bit too much to encapsulate what we need to implement ourselves.

Spring Cloud Gateway only supports webFlux, so we use the @enableWebFluxSecurity annotation.

We configured the Gateway as a Resource Server, and after all, Spring-Security did a lot of things for us, so we had very little code to configure ourselves.

@Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
        http.authorizeExchange()
                .pathMatchers("/actuator/**").permitAll()
                .anyExchange().authenticated();

        http.oauth2ResourceServer().jwt();

        return http.build();
    }
Copy the code

Since our Authorization Server uses JWT tokens, JWT is suitable for use as stateless authentication credentials in pure RESTful apis. With Spring Security OAuth2, it is simple and easy to use. Of course, if a JWT token needs to be revoked in some scenarios, it can also be managed with Redis.

In the code above we declare gateway-service as a simple Resource Server and enable JWT, which is validated by a public key. Therefore, we need to specify the public key address for JWT authentication.

spring.security.oauth2.resourceserver.jwt:
    jwk-set-uri: 'http://localhost:8081/.well-known/jwks.json'
Copy the code

After the above configuration, we have implemented a relatively simple gateway service under the microservices architecture.

The source code

You can download the project source code to try it out: github.com/steventong/…

Also welcome to follow my wechat official account: Steven Tong