首页 短视频

微服务网关 JWT 认证:统一身份验证最佳实践

分类:短视频
字数: (6159)
阅读: (1647)
内容摘要:微服务网关 JWT 认证:统一身份验证最佳实践,

在微服务架构中,服务数量的增加导致身份验证和授权变得越来越复杂。为解决这个问题,通常采用 API 网关作为统一入口,负责请求路由、流量控制、安全认证等。本文将深入探讨如何在网关层集成 JWT (JSON Web Token) 身份认证,实现微服务统一认证,并分享实战中的一些避坑经验。

身份认证痛点:微服务面临的挑战

传统的单体应用中,身份验证通常由应用本身负责。但在微服务架构下,每个服务都可能需要进行身份验证,这导致了以下问题:

  • 重复代码: 每个服务都需要实现身份验证逻辑,造成代码冗余。
  • 安全风险: 各个服务的身份验证机制可能不一致,容易出现安全漏洞。
  • 维护困难: 修改身份验证逻辑需要修改所有服务,维护成本高昂。
  • 跨域问题: 前端应用需要与多个微服务交互,可能存在跨域请求问题。

JWT 认证原理与优势

JSON Web Token (JWT) 是一种基于 JSON 的开放标准 (RFC 7519),用于在各方之间安全地传输信息。一个 JWT 包含三个部分:

微服务网关 JWT 认证:统一身份验证最佳实践
  • Header (头部): 描述 JWT 的类型和使用的加密算法。
  • Payload (载荷): 包含声明 (claims),例如用户身份信息、过期时间等。
  • Signature (签名): 由 Header、Payload 和密钥使用指定的加密算法生成,用于验证 JWT 的完整性和真实性。

JWT 认证的优势在于:

  • 无状态: 服务端不需要存储会话信息,减轻服务器压力,便于水平扩展。
  • 安全: 使用数字签名保证 JWT 的完整性和真实性。
  • 可扩展: 可以在 Payload 中添加自定义声明,满足不同的业务需求。
  • 跨域友好: JWT 可以作为 Cookie 或 HTTP Header 传递,方便跨域请求。

Gateway 集成 JWT 身份认证的实践方案

我们以 Spring Cloud Gateway 为例,演示如何在网关层集成 JWT 身份认证。

微服务网关 JWT 认证:统一身份验证最佳实践

1. 添加依赖

首先,在 pom.xml 文件中添加 Spring Cloud Gateway 和 JWT 相关依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>0.11.5</version>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-impl</artifactId>
    <version>0.11.5</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-jackson</artifactId>
    <version>0.11.5</version>
    <scope>runtime</scope>
</dependency>

2. 创建 JWT 工具类

创建一个 JwtUtil 类,用于生成和解析 JWT:

微服务网关 JWT 认证:统一身份验证最佳实践
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.Map;

@Component
public class JwtUtil {

    @Value("${jwt.secret}") // 从 application.yml 读取 JWT 密钥
    private String secret;

    @Value("${jwt.expiration}") // 从 application.yml 读取 JWT 过期时间
    private Long expiration;

    // 生成 JWT
    public String generateToken(Map<String, Object> claims) {
        Date now = new Date();
        Date expiryDate = new Date(now.getTime() + expiration * 1000);

        return Jwts.builder()
                .setClaims(claims)
                .setIssuedAt(now)
                .setExpiration(expiryDate)
                .signWith(SignatureAlgorithm.HS512, secret)
                .compact();
    }

    // 解析 JWT
    public Claims getClaimsFromToken(String token) {
        try {
            return Jwts.parser()
                    .setSigningKey(secret)
                    .parseClaimsJws(token)
                    .getBody();
        } catch (Exception e) {
            return null; // JWT 解析失败
        }
    }

    // 验证 JWT 是否过期
    public boolean isTokenExpired(String token) {
        Claims claims = getClaimsFromToken(token);
        if (claims == null) {
            return true; // JWT 无效,视为过期
        }
        Date expirationDate = claims.getExpiration();
        return expirationDate.before(new Date());
    }
}

3. 创建 Gateway Filter

创建一个 Gateway Filter,用于拦截请求并验证 JWT。你可以继承 AbstractGatewayFilterFactory 并实现 apply 方法。

import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Arrays;
import java.util.List;

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

    private final JwtUtil jwtUtil;

    public JwtAuthGatewayFilterFactory(JwtUtil jwtUtil) {
        super(Config.class);
        this.jwtUtil = jwtUtil;
    }

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();

            // 从 Header 中获取 JWT
            String token = request.getHeaders().getFirst("Authorization");

            if (StringUtils.isEmpty(token) || !token.startsWith("Bearer ")) {
                return onError(exchange, "Missing or invalid Authorization header", HttpStatus.UNAUTHORIZED);
            }

            token = token.substring(7); // 去掉 "Bearer " 前缀

            if (jwtUtil.isTokenExpired(token)) {
                return onError(exchange, "Token is expired", HttpStatus.UNAUTHORIZED);
            }

            // 可以从 JWT 中提取用户信息,并添加到请求头中,传递给下游服务
            // Claims claims = jwtUtil.getClaimsFromToken(token);
            // request = exchange.getRequest().mutate()
            //         .header("X-User-Id", claims.get("userId", String.class))
            //         .build();

            return chain.filter(exchange.mutate().request(request).build());
        };
    }

    private Mono<Void> onError(ServerWebExchange exchange, String err, HttpStatus httpStatus) {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(httpStatus);
        return response.setComplete();
    }

    public static class Config {
        // 可以添加自定义配置项,例如需要放行的 URL 列表
        private List<String> permitUrls = Arrays.asList("/auth/login", "/auth/register");

        public List<String> getPermitUrls() {
            return permitUrls;
        }

        public void setPermitUrls(List<String> permitUrls) {
            this.permitUrls = permitUrls;
        }
    }
}

4. 配置路由规则

application.yml 中配置路由规则,并应用 JWT 认证 Filter:

微服务网关 JWT 认证:统一身份验证最佳实践
spring:
  cloud:
    gateway:
      routes:
        - id: user-service
          uri: lb://user-service # 使用服务发现,例如 Eureka
          predicates:
            - Path=/user/**
          filters:
            - JwtAuth

5. 客户端请求

客户端在请求时,需要在 HTTP Header 中添加 Authorization 字段,值为 Bearer <JWT>。例如:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

实战避坑经验

  • 密钥安全: JWT 密钥必须妥善保管,避免泄露。可以使用环境变量或配置中心管理密钥。
  • 过期时间: 设置合理的 JWT 过期时间,避免 JWT 被长期滥用。过短的过期时间可能导致频繁刷新 Token,影响用户体验。
  • 刷新 Token: 实现刷新 Token 机制,允许用户在 Token 过期前重新获取新的 Token,避免重新登录。
  • 黑名单机制: 实现 JWT 黑名单机制,当用户注销或发生安全事件时,可以立即失效 JWT。
  • 参数校验: 对 JWT 中的声明进行校验,确保数据的合法性。
  • 性能优化: 如果网关的并发连接数很高,需要考虑 JWT 验证的性能,可以使用缓存等技术进行优化。
  • 监控告警: 监控 JWT 的生成和验证情况,及时发现异常。

在实际项目中,可以结合 Nginx 的反向代理和负载均衡能力,构建高可用、高性能的 API 网关。还可以使用宝塔面板等工具简化服务器运维工作。通过 Gateway 集成 JWT 身份认证,可以实现微服务统一认证,提高系统的安全性和可维护性。

微服务网关 JWT 认证:统一身份验证最佳实践

转载请注明出处: 代码一只喵

本文的链接地址: http://m.acea1.store/article/10073.html

本文最后 发布于2026-04-08 01:42:54,已经过了19天没有更新,若内容或图片 失效,请留言反馈

()
您可能对以下文章感兴趣
评论
  • 海王本王 4 天前
    refreshToken 机制也很关键,不然用户体验太差了,动不动就要重新登录。
  • 干饭人 5 天前
    refreshToken 机制也很关键,不然用户体验太差了,动不动就要重新登录。
  • 社畜一枚 4 天前
    请问楼主,如果我想集成 Oauth2,思路也是类似的吗?