淘宝客app的API网关设计:认证授权与流量控制策略

淘宝客app的API网关设计:认证授权与流量控制策略

大家好,我是阿可,微赚淘客系统及省赚客APP创始人,是个冬天不穿秋裤,天冷也要风度的程序猿!

在淘宝客app的微服务架构中,随着商品服务、订单服务、返利服务等10+微服务的拆分,前端调用面临接口分散、认证逻辑重复、流量难以管控等问题------比如每个服务都要单独实现用户登录校验,大促期间商品查询接口易因流量突增崩溃。基于此,我们引入Spring Cloud Gateway作为API网关 ,将认证授权、流量控制、请求路由等共性能力收敛到网关层,实现"前端-网关-微服务"的统一接入架构。以下从网关整体设计、认证授权实现、流量控制策略三方面展开,附完整代码示例。

一、淘宝客app API网关整体架构

1.1 网关核心职责与技术选型

API网关作为淘宝客app的"流量入口",承担四大核心职责:

  1. 请求路由 :根据URL路径将请求转发至对应微服务(如/api/product/**转发至商品服务);
  2. 认证授权:统一校验用户Token,拦截未登录请求,校验接口访问权限;
  3. 流量控制:对高频接口(如商品列表查询)进行限流、熔断,保护后端服务;
  4. 监控日志:记录请求耗时、响应状态,便于问题排查与链路追踪。

技术选型上,采用Spring Cloud Gateway(非阻塞异步架构,性能优于Zuul),搭配Redis实现分布式限流,结合JWT实现Token认证,架构图如下(文字描述):前端请求→API网关(认证/限流/路由)→微服务集群→网关聚合响应→返回前端。

1.2 网关基础配置(application.yml)

通过配置文件定义路由规则、全局过滤器、Redis限流数据源,代码如下:

yaml 复制代码
spring:
  cloud:
    gateway:
      # 路由规则配置
      routes:
        # 商品服务路由
        - id: product-service-route
          uri: lb://product-service  # 负载均衡到商品服务(服务名从Nacos获取)
          predicates:
            - Path=/api/product/**  # 匹配路径
          filters:
            - StripPrefix=1  # 去除路径前缀(/api/product/xxx → /product/xxx)
            - name: RequestRateLimiter  # 限流过滤器
              args:
                redis-rate-limiter.replenishRate: 100  # 令牌桶每秒填充速率
                redis-rate-limiter.burstCapacity: 200  # 令牌桶最大容量
                key-resolver: "#{@userKeyResolver}"  # 限流键解析器(用户维度)
            - name: AuthFilter  # 自定义认证过滤器
              args:
                ignorePaths: /api/product/info  # 无需认证的接口(如商品详情)
        # 订单服务路由
        - id: order-service-route
          uri: lb://order-service
          predicates:
            - Path=/api/order/**
          filters:
            - StripPrefix=1
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 50
                redis-rate-limiter.burstCapacity: 100
                key-resolver: "#{@userKeyResolver}"
  # Redis配置(用于限流与Token缓存)
  redis:
    host: redis-service
    port: 6379
    password: TaokeRedis@2024
    lettuce:
      pool:
        max-active: 16
        max-idle: 8

# 网关服务端口
server:
  port: 8080

# 日志配置(记录请求详情)
logging:
  level:
    org.springframework.cloud.gateway: info
    cn.juwatech.taoke.gateway: debug

二、认证授权核心实现

2.1 JWT Token生成与校验工具类

封装JWT的创建、解析、签名验证逻辑,代码如下:

java 复制代码
package cn.juwatech.taoke.gateway.utils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * JWT工具类(生成Token、解析Token、验证Token)
 */
@Component
public class JwtUtils {
    // 密钥(从配置中心获取,避免硬编码)
    @Value("${taoke.jwt.secret:juwatech_taoke_secret_2024}")
    private String secret;
    // Token有效期(2小时,单位:毫秒)
    @Value("${taoke.jwt.expire:7200000}")
    private long expire;

    /**
     * 生成用户Token(包含用户ID、用户名、角色)
     */
    public String generateToken(String userId, String username, String role) {
        // Token过期时间
        Date expireDate = new Date(System.currentTimeMillis() + expire);
        // 自定义Claims(携带业务信息)
        Map<String, Object> claims = new HashMap<>();
        claims.put("userId", userId);
        claims.put("username", username);
        claims.put("role", role);

        return Jwts.builder()
                .setClaims(claims)
                .setExpiration(expireDate)
                .signWith(SignatureAlgorithm.HS256, secret)  // HS256签名算法
                .compact();
    }

    /**
     * 解析Token,获取Claims
     */
    public Claims parseToken(String token) {
        try {
            return Jwts.parser()
                    .setSigningKey(secret)
                    .parseClaimsJws(token)
                    .getBody();
        } catch (Exception e) {
            throw new RuntimeException("Token解析失败:" + e.getMessage());
        }
    }

    /**
     * 验证Token有效性(是否过期、签名是否正确)
     */
    public boolean validateToken(String token) {
        try {
            Claims claims = parseToken(token);
            // 检查Token是否过期
            return !claims.getExpiration().before(new Date());
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 从Token中获取用户ID
     */
    public String getUserIdFromToken(String token) {
        Claims claims = parseToken(token);
        return claims.get("userId", String.class);
    }

    /**
     * 从Token中获取用户角色
     */
    public String getRoleFromToken(String token) {
        Claims claims = parseToken(token);
        return claims.get("role", String.class);
    }
}

2.2 自定义认证过滤器(AuthFilter)

实现GlobalFilter接口,在网关层统一拦截请求,校验Token与接口权限,代码如下:

java 复制代码
package cn.juwatech.taoke.gateway.filter;

import cn.juwatech.taoke.gateway.utils.JwtUtils;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.util.List;

/**
 * 认证授权全局过滤器(Order=1,优先执行)
 */
@Configuration
public class AuthFilterConfig {
    // 路径匹配器(用于判断是否忽略认证)
    private final AntPathMatcher pathMatcher = new AntPathMatcher();
    // 注入JWT工具类
    @Resource
    private JwtUtils jwtUtils;

    @Bean
    @Order(1)
    public GlobalFilter authFilter() {
        return (exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();
            ServerHttpResponse response = exchange.getResponse();
            String requestPath = request.getPath().value();

            // 1. 获取无需认证的路径列表(从路由过滤器参数中获取)
            List<String> ignorePaths = exchange.getAttribute("ignorePaths");
            if (ignorePaths != null && ignorePaths.stream().anyMatch(path -> pathMatcher.match(path, requestPath))) {
                // 无需认证,直接放行
                return chain.filter(exchange);
            }

            // 2. 从请求头获取Token(格式:Bearer {token})
            String authHeader = request.getHeaders().getFirst("Authorization");
            if (!StringUtils.hasText(authHeader) || !authHeader.startsWith("Bearer ")) {
                // Token不存在或格式错误,返回401未授权
                response.setStatusCode(HttpStatus.UNAUTHORIZED);
                return response.writeWith(Mono.just(response.bufferFactory().wrap("请先登录".getBytes())));
            }
            String token = authHeader.substring(7);

            // 3. 验证Token有效性
            if (!jwtUtils.validateToken(token)) {
                response.setStatusCode(HttpStatus.UNAUTHORIZED);
                return response.writeWith(Mono.just(response.bufferFactory().wrap("Token已过期或无效".getBytes())));
            }

            // 4. 校验接口访问权限(示例:管理员角色才能访问订单管理接口)
            String role = jwtUtils.getRoleFromToken(token);
            if (requestPath.startsWith("/api/order/admin/") && !"ADMIN".equals(role)) {
                response.setStatusCode(HttpStatus.FORBIDDEN);
                return response.writeWith(Mono.just(response.bufferFactory().wrap("无权限访问".getBytes())));
            }

            // 5. Token有效且有权限,将用户信息存入请求头,传递给后端服务
            String userId = jwtUtils.getUserIdFromToken(token);
            ServerHttpRequest newRequest = request.mutate()
                    .header("X-User-Id", userId)
                    .header("X-User-Role", role)
                    .build();
            return chain.filter(exchange.mutate().request(newRequest).build());
        };
    }
}

三、流量控制策略实现

3.1 分布式限流键解析器

基于用户ID实现分布式限流(不同用户独立计数),避免单用户高频请求影响其他用户,代码如下:

java 复制代码
package cn.juwatech.taoke.gateway.config;

import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import reactor.core.publisher.Mono;

/**
 * 限流键解析器配置(用户维度限流)
 */
@Configuration
public class RateLimiterConfig {
    /**
     * 用户维度限流键解析器(从Token或请求参数获取用户ID)
     */
    @Bean("userKeyResolver")
    public KeyResolver userKeyResolver() {
        return exchange -> {
            // 1. 从请求头获取用户ID(已通过认证的请求,由AuthFilter注入)
            String userId = exchange.getRequest().getHeaders().getFirst("X-User-Id");
            if (StringUtils.hasText(userId)) {
                return Mono.just(userId);
            }

            // 2. 未认证请求(如商品详情查询),从请求参数获取设备ID(避免匿名用户限流冲突)
            String deviceId = exchange.getRequest().getQueryParams().getFirst("deviceId");
            if (StringUtils.hasText(deviceId)) {
                return Mono.just(deviceId);
            }

            // 3. 无设备ID,返回默认键(所有匿名请求共享一个限流额度)
            return Mono.just("default_anonymous");
        };
    }

    /**
     * 接口维度限流键解析器(可选,按接口路径限流)
     */
    @Bean("apiKeyResolver")
    public KeyResolver apiKeyResolver() {
        return exchange -> {
            String path = exchange.getRequest().getURI().getPath();
            return Mono.just(path);
        };
    }
}

3.2 熔断降级配置(Resilience4j)

整合Resilience4j实现服务熔断,当后端服务(如订单服务)连续报错超过阈值时,触发熔断并返回默认降级响应,代码如下:

yaml 复制代码
# 在application.yml中添加熔断配置
spring:
  cloud:
    gateway:
      routes:
        - id: order-service-route
          # 其他配置省略...
          filters:
            - name: CircuitBreaker  # 熔断过滤器
              args:
                name: orderServiceCircuitBreaker  # 熔断实例名
                fallbackUri: forward:/fallback/order  # 降级回调接口

# Resilience4j熔断配置
resilience4j:
  circuitbreaker:
    instances:
      orderServiceCircuitBreaker:
        slidingWindowSize: 10  # 滑动窗口大小(10个请求)
        failureRateThreshold: 50  # 失败率阈值(50%)
        waitDurationInOpenState: 60000  # 熔断打开状态持续时间(60秒)
        permittedNumberOfCallsInHalfOpenState: 3  # 半开状态允许请求数(3个)

3.3 降级回调接口实现

定义熔断后的降级响应接口,返回友好提示,代码如下:

java 复制代码
package cn.juwatech.taoke.gateway.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;

import java.util.HashMap;
import java.util.Map;

/**
 * 熔断降级回调接口
 */
@RestController
public class FallbackController {
    /**
     * 订单服务降级响应
     */
    @GetMapping("/fallback/order")
    public Mono<Map<String, Object>> orderFallback() {
        Map<String, Object> result = new HashMap<>();
        result.put("code", 503);
        result.put("message", "订单服务暂时繁忙,请稍后重试");
        result.put("data", null);
        return Mono.just(result);
    }

    /**
     * 商品服务降级响应
     */
    @GetMapping("/fallback/product")
    public Mono<Map<String, Object>> productFallback() {
        Map<String, Object> result = new HashMap<>();
        result.put("code", 503);
        result.put("message", "商品查询服务暂时繁忙,建议稍后刷新");
        result.put("data", null);
        return Mono.just(result);
    }
}

四、网关监控与优化

  1. 监控指标采集 :通过Spring Boot Actuator暴露网关指标(如/actuator/prometheus),结合Prometheus+Grafana监控请求量、限流次数、熔断次数;
  2. 性能优化 :开启网关请求压缩(spring.cloud.gateway.httpclient.compress: true),减少网络传输量;调整Netty线程池大小(spring.cloud.gateway.httpclient.threads.eventLoopCount: 16),提升并发处理能力;
  3. 安全加固 :配置HTTPS(server.ssl相关参数),强制前端使用加密协议;通过网关过滤器过滤SQL注入、XSS攻击等恶意请求参数。

本文著作权归聚娃科技省赚客app开发者团队,转载请注明出处!

相关推荐
孟意昶2 小时前
Spark专题-第一部分:Spark 核心概述(1)-Spark 是什么?
大数据·分布式·spark
努力努力再努力wz2 小时前
【c++进阶系列】:map和set的模拟实现(附模拟实现的源码)
java·linux·运维·开发语言·c++
Cloud Traveler3 小时前
8.FC平台模块梳理
java·linux·开发语言
码农小伙4 小时前
单体到微服务拆分方案
微服务·架构
u0104058364 小时前
京东返利app的分布式ID生成策略:雪花算法在订单系统中的实践
分布式·算法
AcrelZYL4 小时前
工商业屋顶分布式光伏监控系统助力园区企业错峰有序用电
分布式·分布式光伏·屋顶分布式光伏·工商业分布式光伏监控
thginWalker4 小时前
分布式协议与算法实战-理论篇
分布式
失散135 小时前
分布式专题——10.2 ShardingSphere-JDBC分库分表实战与讲解
java·分布式·架构·shardingsphere·分库分表
失散137 小时前
分布式专题——10.4 ShardingSphere-Proxy服务端分库分表
java·分布式·架构·shardingsphere·分库分表