SpringBoot + SpringCloud Gateway + Sentinel + Redis:API 网关层的接口限流、黑名单拦截与用户认证

SpringBoot + SpringCloud Gateway + Sentinel + Redis:API 网关层的接口限流、黑名单拦截与用户认证

今天和大家分享一个我们在生产环境中稳定运行的API网关解决方案——基于SpringBoot + SpringCloud Gateway + Sentinel + Redis的组合,实现接口限流、黑名单拦截和用户认证三大核心功能。

一、为什么需要API网关层的安全控制?

在微服务架构盛行的今天,我们的系统被拆分成数十甚至上百个独立的服务。如果没有一个统一的入口来管理这些服务的访问,将会面临以下风险:

  1. 恶意请求泛滥:攻击者可能通过大量无效请求消耗服务器资源
  2. 非法用户访问:未授权用户可能访问敏感接口
  3. 黑名单用户绕过:被封禁的用户可能通过不同IP或设备继续访问
  4. 系统雪崩风险:突发流量可能导致整个系统瘫痪

这就需要我们在API网关层建立一道坚固的防线。

二、整体架构设计思路

我们的解决方案采用了四层防护体系:

客户端请求 → SpringCloud Gateway → Sentinel限流 → 黑名单拦截 → JWT认证 → 目标服务

每一层都有其特定的职责:

  • Sentinel限流:控制请求频率,防止系统过载
  • 黑名单拦截:阻止恶意用户和IP访问
  • JWT认证:验证用户身份合法性

三、核心技术实现

1. Sentinel实现精准限流

Sentinel作为阿里巴巴开源的流量控制组件,在我们的方案中承担着流量整形的重要职责。

// 限流规则配置
@Configuration
public class SentinelConfig {
    
    @PostConstruct
    public void initFlowRules() {
        List<FlowRule> rules = new ArrayList<>();
        
        // 对用户接口进行限流,每秒最多100个请求
        FlowRule rule = new FlowRule();
        rule.setResource("/api/user/**");
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        rule.setCount(100);
        rules.add(rule);
        
        // 对订单接口进行限流,每秒最多50个请求
        FlowRule orderRule = new FlowRule();
        orderRule.setResource("/api/order/**");
        orderRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        orderRule.setCount(50);
        rules.add(orderRule);
        
        FlowRuleManager.loadRules(rules);
    }
}

2. Redis实现高效黑名单拦截

我们使用Redis的Hash数据结构来存储黑名单信息,支持按用户ID和IP地址两种维度进行拦截。

@Component
public class BlackListInterceptor implements GlobalFilter {
    
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        
        // 获取用户ID和IP地址
        String userId = getUserIdFromRequest(request);
        String clientIp = getClientIp(request);
        
        // 检查是否在黑名单中
        if (isInBlackList(userId, clientIp)) {
            ServerHttpResponse response = exchange.getResponse();
            response.setStatusCode(HttpStatus.FORBIDDEN);
            String data = "{\"code\": 403, \"message\": \"您已被限制访问\"}";
            DataBuffer buffer = response.bufferFactory().wrap(data.getBytes(StandardCharsets.UTF_8));
            response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
            return response.writeWith(Mono.just(buffer));
        }
        
        return chain.filter(exchange);
    }
    
    private boolean isInBlackList(String userId, String clientIp) {
        // 检查用户ID是否在黑名单中
        Boolean userBlocked = redisTemplate.hasKey("blacklist:user:" + userId);
        if (Boolean.TRUE.equals(userBlocked)) {
            return true;
        }
        
        // 检查IP是否在黑名单中
        Boolean ipBlocked = redisTemplate.hasKey("blacklist:ip:" + clientIp);
        return Boolean.TRUE.equals(ipBlocked);
    }
}

3. JWT实现无状态认证

JWT令牌的使用让我们可以实现无状态的用户认证,大大减轻了服务器的压力。

@Component
public class JwtAuthenticationFilter implements GlobalFilter {
    
    @Autowired
    private JwtUtil jwtUtil;
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        
        // 从Header中获取token
        String token = getTokenFromHeader(request);
        
        if (token != null && jwtUtil.validateToken(token)) {
            // 解析用户信息并放入请求上下文
            Claims claims = jwtUtil.getClaimsFromToken(token);
            String userId = claims.getSubject();
            
            // 将用户信息添加到请求头中
            ServerHttpRequest mutatedRequest = request.mutate()
                    .header("X-USER-ID", userId)
                    .build();
            
            ServerWebExchange mutatedExchange = exchange.mutate()
                    .request(mutatedRequest)
                    .build();
                    
            return chain.filter(mutatedExchange);
        }
        
        // token无效,返回401
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        String data = "{\"code\": 401, \"message\": \"未授权访问\"}";
        DataBuffer buffer = response.bufferFactory().wrap(data.getBytes(StandardCharsets.UTF_8));
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        return response.writeWith(Mono.just(buffer));
    }
}

四、配置集成与使用

为了让这三个组件协同工作,我们需要在application.yml中进行相应配置:

spring:
  cloud:
    gateway:
      routes:
        - id: user-service
          uri: lb://user-service
          predicates:
            - Path=/api/user/**
          filters:
            - StripPrefix=2
            
  redis:
    host: localhost
    port: 6379
    timeout: 2000ms

jwt:
  secret: mySecretKey
  expiration: 86400

五、性能优化要点

在实际部署中,我们还做了以下性能优化:

  1. Redis连接池优化:合理配置连接池大小,避免连接瓶颈
  2. 缓存预热:系统启动时预加载热点黑名单数据
  3. 异步处理:对于非核心的拦截逻辑采用异步处理
  4. 监控告警:接入Prometheus和Grafana,实时监控网关性能

六、生产环境实战效果

自上线以来,这套API网关方案在我们的生产环境中表现优异:

  1. 拦截效果显著:平均每天拦截恶意请求超过10万次
  2. 系统稳定性提升:接口响应时间保持在50ms以内
  3. 资源利用率优化:服务器CPU使用率下降30%
  4. 运维成本降低:通过自动化封禁减少了90%的人工干预

七、常见问题与解决方案

1. 限流策略如何制定?

根据不同业务场景设置不同的限流阈值,可以通过AB测试逐步调整到最优值。

2. 黑名单如何管理?

建立完善的黑名单管理系统,支持手动添加和自动识别两种模式。

3. JWT安全性如何保障?

定期更换密钥,设置合理的过期时间,使用HTTPS传输。

八、总结

API网关作为微服务架构的第一道防线,其重要性不言而喻。通过SpringBoot + SpringCloud Gateway + Sentinel + Redis的组合,我们构建了一套高可用、高性能的安全防护体系。

这套方案不仅解决了我们面临的实际问题,也为后续的功能扩展留下了充足的空间。希望今天的分享能给大家在API网关设计方面带来一些启发。


作者简介
十年后端架构师,专注于微服务架构和云原生技术,曾主导多个大型互联网项目的架构设计与实施。目前专注于高并发系统优化和分布式系统治理。

关注我,获取更多实用的技术干货!


标题:SpringBoot + SpringCloud Gateway + Sentinel + Redis:API 网关层的接口限流、黑名单拦截与用户认证
作者:jiangyi
地址:http://www.jiangyi.space/articles/2025/12/21/1766304279076.html

    0 评论
avatar