首页 数字经济

微服务网关 JWT 认证:统一身份认证架构实战

分类:数字经济
字数: (4490)
阅读: (3551)
内容摘要:微服务网关 JWT 认证:统一身份认证架构实战,

在微服务架构中,服务拆分带来灵活性的同时,也引入了复杂的身份认证和授权问题。每个微服务都进行单独的认证,不仅增加开发和维护成本,也影响用户体验。本文将分享如何利用 Gateway 集成 JWT 身份认证,实现微服务统一认证,并分享一些实战中的避坑经验。

问题场景:微服务认证的困境

假设我们有一个电商平台,包含用户服务、商品服务、订单服务等多个微服务。如果每个服务都各自进行用户认证,会导致:

  • 重复开发: 每个服务都需要编写认证逻辑,增加开发工作量。
  • 维护困难: 用户信息变更时,需要在多个服务中同步,容易出错。
  • 安全风险: 每个服务都需要独立管理密钥,容易出现安全漏洞。
  • 用户体验差: 用户每次访问不同服务都需要重新登录。

因此,我们需要一个统一的认证中心,负责处理所有用户的身份验证,并生成令牌(Token)供各个服务使用。Gateway 作为流量入口,是集成统一认证的理想位置。

微服务网关 JWT 认证:统一身份认证架构实战

底层原理:JWT 认证流程

JWT(JSON Web Token)是一种基于 JSON 的开放标准(RFC 7519),用于在各方之间安全地传递声明。JWT 通常包含以下三个部分:

  • Header(头部): 包含令牌类型和使用的签名算法。
  • Payload(载荷): 包含声明(Claims),例如用户ID、用户名、权限等。
  • Signature(签名): 通过头部指定的算法对头部和载荷进行签名,防止篡改。

使用 JWT 进行身份认证的流程如下:

微服务网关 JWT 认证:统一身份认证架构实战
  1. 用户向认证服务器(例如,用户服务)提供用户名和密码进行登录。
  2. 认证服务器验证用户身份,如果验证成功,则生成 JWT 并返回给客户端。
  3. 客户端将 JWT 存储在本地(例如,Cookie 或 LocalStorage)。
  4. 客户端每次请求微服务时,都将 JWT 放在请求头中(例如,Authorization: Bearer <token>)。
  5. Gateway 接收到请求后,验证 JWT 的有效性。
  6. 如果 JWT 有效,则提取 JWT 中的信息(例如,用户ID、权限),并将这些信息添加到请求头中,然后将请求转发给相应的微服务。
  7. 微服务根据请求头中的信息进行授权。

代码/配置解决方案:Spring Cloud Gateway + Spring Security + JWT

以下是一个基于 Spring Cloud Gateway、Spring Security 和 JWT 实现统一认证的示例:

1. 添加依赖

pom.xml 文件中添加以下依赖:

微服务网关 JWT 认证:统一身份认证架构实战
<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</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>
</dependencies>

2. JWT 工具类

创建一个 JWT 工具类,用于生成和验证 JWT:

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import org.springframework.stereotype.Component;

import javax.crypto.SecretKey;
import java.util.Date;
import java.util.function.Function;

@Component
public class JwtUtil {

    private final SecretKey secretKey = Keys.secretKeyFor(SignatureAlgorithm.HS512); // 密钥,生产环境应使用更安全的方式存储

    public String generateToken(String subject) {
        return Jwts.builder()
                .setSubject(subject)
                .setIssuedAt(new Date(System.currentTimeMillis()))
                .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10)) // 10 小时过期
                .signWith(secretKey)
                .compact();
    }

    public boolean validateToken(String token) {
        return !isTokenExpired(token);
    }

    private boolean isTokenExpired(String token) {
        return extractExpiration(token).before(new Date());
    }

    public Date extractExpiration(String token) {
        return extractClaim(token, Claims::getExpiration);
    }

    public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
        final Claims claims = extractAllClaims(token);
        return claimsResolver.apply(claims);
    }

    private Claims extractAllClaims(String token) {
        return Jwts.parserBuilder().setSigningKey(secretKey).build().parseClaimsJws(token).getBody();
    }

    public String extractUsername(String token) {
        return extractClaim(token, Claims::getSubject);
    }
}

3. Spring Security 配置

配置 Spring Security,添加 JWT 过滤器:

微服务网关 JWT 认证:统一身份认证架构实战
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.SecurityWebFiltersOrder;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.authentication.AuthenticationWebFilter;

@EnableWebFluxSecurity
public class SecurityConfig {

    @Autowired
    private JwtUtil jwtUtil;

    @Bean
    public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http, JwtAuthenticationConverter jwtAuthenticationConverter) {
        return http
                .csrf().disable()
                .authorizeExchange()
                .pathMatchers("/auth/**").permitAll() // 允许访问 /auth/** 接口,例如登录、注册
                .anyExchange().authenticated() // 其他所有请求需要认证
                .and()
                .addFilterAt(new JwtAuthenticationFilter(jwtUtil), SecurityWebFiltersOrder.AUTHENTICATION)
                .build();   
    }

    @Bean
    public JwtAuthenticationConverter jwtAuthenticationConverter() {
        return new JwtAuthenticationConverter();
    }
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;

@Component
public class JwtAuthenticationFilter implements WebFilter {

    @Autowired
    private JwtUtil jwtUtil;

    public JwtAuthenticationFilter(JwtUtil jwtUtil) {
        this.jwtUtil = jwtUtil;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        String authHeader = exchange.getRequest().getHeaders().getFirst(HttpHeaders.AUTHORIZATION);

        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            String token = authHeader.substring(7); // 去掉 "Bearer " 前缀
            if (jwtUtil.validateToken(token)) {
                String username = jwtUtil.extractUsername(token);
                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(username, null, null); // 没有权限信息
                return chain.filter(exchange).contextWrite(ReactiveSecurityContextHolder.withAuthentication(authentication));
            }
        }

        return chain.filter(exchange);
    }
}

4. Gateway 路由配置

application.ymlapplication.properties 文件中配置 Gateway 路由规则:

spring:
  cloud:
    gateway:
      routes:
        - id: user-service
          uri: lb://user-service # 使用服务发现
          predicates:
            - Path=/user/**
          filters:
            - AddRequestHeader=X-Request-User, #[{authentication_principal}]

5. 用户服务提供认证接口

创建一个 /auth/login 接口,用于用户登录并返回 JWT。

实战避坑经验总结

  • 密钥管理: JWT 的密钥至关重要,必须安全存储,防止泄露。可以使用 Vault 等密钥管理工具。
  • Token 过期时间: 合理设置 Token 的过期时间,避免 Token 被滥用。可以根据业务需求设置不同的过期时间。
  • 刷新 Token: 为了避免用户频繁登录,可以实现刷新 Token 的机制。当 Token 即将过期时,客户端可以向认证服务器请求新的 Token。
  • JWT 的大小: JWT 不宜过大,避免影响网络传输性能。尽量减少在 Payload 中包含的信息。
  • 安全性: JWT 只是验证用户身份,不能防止 CSRF 攻击。对于敏感操作,仍需要使用 CSRF 防护。
  • 监控和日志: 监控 Gateway 的认证和授权情况,记录必要的日志,方便排查问题。
  • 性能优化: 使用缓存机制,减少 JWT 的验证次数,提高 Gateway 的性能。例如使用 Redis 缓存 JWT 验证结果。

通过以上方案,我们可以在 Gateway 中集成 JWT 身份认证,实现微服务统一认证,简化开发和维护工作,并提升用户体验。同时,在实际应用中,还需要根据具体业务场景进行调整和优化,例如使用 OAuth 2.0 协议,或集成第三方认证服务。

Nginx 作为常用的反向代理服务器,也可以与 Gateway 配合使用,提高系统的可用性和可扩展性。 例如通过 Nginx 负载均衡,将流量分发到多个 Gateway 实例,保证系统的高可用性。

微服务网关 JWT 认证:统一身份认证架构实战

转载请注明出处: 加班到秃头

本文的链接地址: http://m.acea1.store/blog/425384.SHTML

本文最后 发布于2026-04-26 21:59:09,已经过了1天没有更新,若内容或图片 失效,请留言反馈

()
您可能对以下文章感兴趣
评论
  • 键盘侠本侠 7 小时前
    Token 过期时间设置太短用户体验不好,太长又有安全风险,这个度确实不好把握。
  • 秋名山车神 4 天前
    JWT 认证确实很方便,但是密钥管理是个大问题,有没有更安全的方案推荐?
  • 芒果布丁 6 天前
    JWT 认证确实很方便,但是密钥管理是个大问题,有没有更安全的方案推荐?