Backend Development 11 min read

Building a Spring Cloud Gateway Service with Nacos Dynamic Routing and Authentication Filter

This tutorial explains how to quickly set up a Spring Cloud Gateway service, configure static and Nacos‑driven dynamic routes, and implement a Redis‑backed authentication filter that validates tokens, refreshes expiration, and forwards user information to downstream services.

Top Architect
Top Architect
Top Architect
Building a Spring Cloud Gateway Service with Nacos Dynamic Routing and Authentication Filter

In this article the author, a senior architect, demonstrates step‑by‑step how to create a gateway service using Spring Cloud Gateway 2.1, configure routes in application.yml , and understand the role of each routing property.

First, add the required Maven dependencies for Spring Boot, Spring Cloud Gateway, and Commons Lang3:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.0.RELEASE</version>
</parent>

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-gateway-core</artifactId>
</dependency>

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
</dependency>

Next, define the static route configuration in application.yml :

server:
  port: 8080
spring:
  cloud:
    gateway:
      enabled: true
      routes:
        - id: demo-server
          uri: http://localhost:8081
          predicates:
            - Path=/demo-server/**
          filters:
            - StripPrefix=1

The table below explains each field (id, uri, predicates, filters). The StripPrefix filter removes the first path segment so that the downstream service receives a clean request path.

To avoid restarting the gateway when routes change, the article introduces dynamic routing with Nacos. After deploying a Nacos instance, the route definitions are stored as JSON in a dataId named routes . The following component listens for changes and updates the gateway at runtime:

@Component
public class NacosDynamicRouteService implements ApplicationEventPublisherAware {
    private static final Logger LOGGER = LoggerFactory.getLogger(NacosDynamicRouteService.class);
    @Autowired
    private RouteDefinitionWriter routeDefinitionWriter;
    private ApplicationEventPublisher applicationEventPublisher;
    private static List
routeIds = Lists.newArrayList();

    @NacosConfigListener(dataId = "routes", groupId = "gateway-server")
    public void routeConfigListener(String configInfo) {
        clearRoute();
        try {
            List
gatewayRouteDefinitions = JSON.parseArray(configInfo, RouteDefinition.class);
            for (RouteDefinition rd : gatewayRouteDefinitions) {
                addRoute(rd);
            }
            publish();
            LOGGER.info("Dynamic Routing Publish Success");
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        }
    }
    // clearRoute, addRoute, publish, setApplicationEventPublisher implementations omitted for brevity
}

For security, the article adds a global authentication filter that extracts a token from headers, query parameters, or cookies, checks its validity against Redis, refreshes the token’s TTL, and injects the user ID into the request header for downstream services.

@Component
public class AuthFilter implements GlobalFilter, Ordered {
    @Autowired
    private RedisTemplate
redisTemplate;
    private static final String TOKEN_HEADER_KEY = "auth_token";

    @Override
    public Mono
filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String token = getToken(request);
        ServerHttpResponse response = exchange.getResponse();
        if (StringUtils.isBlank(token)) {
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }
        String userId = getUserIdByToken(token);
        if (StringUtils.isBlank(userId)) {
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }
        ServerHttpRequest.Builder builder = request.mutate();
        request = builder.header("user_id", userId).build();
        resetTokenExpirationTime(token, userId);
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() { return 0; }

    private String getUserIdByToken(String token) {
        String redisKey = String.join(":", "auth_token", token);
        return redisTemplate.opsForValue().get(redisKey);
    }

    private void resetTokenExpirationTime(String token, String userId) {
        String redisKey = String.join(":", "auth_token", token);
        redisTemplate.opsForValue().set(redisKey, userId, 2, TimeUnit.HOURS);
    }

    private static String getToken(ServerHttpRequest request) {
        HttpHeaders headers = request.getHeaders();
        String token = headers.getFirst(TOKEN_HEADER_KEY);
        if (StringUtils.isBlank(token)) {
            token = request.getQueryParams().getFirst(TOKEN_HEADER_KEY);
        }
        if (StringUtils.isBlank(token)) {
            HttpCookie cookie = request.getCookies().getFirst(TOKEN_HEADER_KEY);
            if (cookie != null) token = cookie.getValue();
        }
        return token;
    }
}

Finally, the article reminds readers that the gateway can be extended with additional filters for rate‑limiting, blacklist checks, etc., and that the whole solution demonstrates a practical, production‑ready approach to routing and authentication in a micro‑service architecture.

JavaRedisNacosDynamic RoutingSpring Cloud GatewayAuthentication Filter
Top Architect
Written by

Top Architect

Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.