当前位置: 首页 > news >正文

微服务 - 网关统一鉴权

一、什么是网关统一鉴权?

网关统一鉴权,顾名思义,就是将原本分散在各个微服务中的身份验证和权限校验逻辑,抽取出来并集中到API网关这一层来统一处理。

  • 传统方式(无网关): 每个微服务(如用户服务、订单服务、支付服务)都需要自己实现一套鉴权逻辑,检查Token是否有效、用户是否有权限访问等。这会导致以下一系列问题:
    • 代码重复与维护困难:每个服务都需要编写和维护相似的鉴权代码,违反了“Don‘t Repeat Yourself”原则。
    • 标准不一:不同的开发团队可能实现不同的鉴权逻辑或安全标准,导致系统整体安全性不一致。
    • 性能瓶颈:每次请求都需要在多个服务中进行重复的鉴权操作(如JWT解析、数据库查询),增加延迟。
    • 耦合度增加:业务服务需要关心非业务性的安全逻辑,与服务无状态、高内聚的设计理念相悖。
  • 统一鉴权方式: 鉴权逻辑只在API网关实现一次。请求到达网关后,网关先进行鉴权,只有通过鉴权的请求才会被转发到后端的微服务。后端微服务可以“信任”网关,无需再次鉴权,只需处理业务逻辑。

二、为什么需要网关统一鉴权?

网关统一鉴权就是为了解决上述问题而生的。它的核心思想是:将鉴权这个横切关注点从各个业务服务中剥离出来,集中到API网关这一层进行处理。其主要好处如下:

  1. 安全性集中管理:
    • 将敏感的安全逻辑集中在一处,避免了安全漏洞分散在各个服务中。一旦发现安全策略需要调整,只需在网关修改,所有服务立即生效。
    • 更容易实施统一的安全标准和审计。
  2. 架构解耦与业务纯净:
    • 后端微服务不再需要关心复杂的鉴权逻辑,可以专注于实现业务功能,使得服务更加“纯净”和“高内聚”。
    • 服务间的耦合度降低,更容易开发和维护。
  3. 提升性能:
    • 对于非法请求(如Token无效、权限不足),网关可以在最外层直接拦截并拒绝,避免了请求穿透到后端服务,节省了宝贵的后端资源。
  4. 统一管控与监控:
    • 可以方便地在网关层统一添加日志、限流、熔断等管控措施。所有认证和授权失败都可以在网关层面被监控和报警。

三、核心思想与流程

  • 核心思想:

    • 前置鉴权。在请求到达内部微服务之前,由网关作为一个统一的“安检站”,对所有请求进行身份验证和权限校验。只有通过检查的请求才会被路由到后端的业务服务;失败的请求则直接被网关拦截并返回错误响应。
  • 基本流程:

    1. 客户端请求:客户端(Web、App等)携带访问令牌(通常是JWT)发起请求。

    2. 请求到达网关:所有外部请求首先到达API网关。

    3. 令牌提取与验证:

      • 网关从请求头(通常是 Authorization: Bearer )或Cookie中提取令牌。
      • 进行基础验证,例如检查令牌结构、签名、是否过期等。
    4. 身份认证:

      • 验证令牌真伪:使用预先配置的密钥或公钥验证JWT的签名。
      • (可选)检查黑名单:查询令牌是否已被注销(如用户已登出)。
    5. 权限鉴定:

      • 从验证通过的令牌中解析出用户信息(如用户ID、角色、权限列表)。
      • 根据请求的路径(URL) 和方法(HTTP Method),判断当前用户是否拥有访问该资源的权限。这一步通常需要查询权限规则或与专门的鉴权服务交互。
    6. 网关决策:

      • 成功:网关将请求(通常会附加解析出的用户信息)路由到目标微服务。微服务无需再次鉴权,可直接处理业务逻辑。
      • 失败:网关直接返回 401 Unauthorized(未认证)或 403 Forbidden(无权限)响应,请求不会到达后端服务。
    7. 请求转发:通过鉴权的请求被转发到相应的业务微服务。

四、 关键技术组件与实现

  1. API网关:

    • Spring Cloud Gateway: 基于Spring 5、Project Reactor的响应式网关,性能高,是当前Spring Cloud生态的首选。
    • Netflix Zuul: Spring Cloud旧版本的网关组件,目前已进入维护模式。
    • Kong / Apache APISIX: 基于Nginx/OpenResty的高性能、云原生API网关,功能强大,插件生态丰富。
  2. 认证与授权协议/技术:

    • JWT: 最流行的无状态令牌。鉴权服务器签发JWT后,网关只需使用公钥验证其签名即可,无需每次请求都去查询数据库或鉴权服务,性能极高。
    • OAuth 2.0 / OIDC: 行业标准的授权框架。网关可以扮演OAuth 2.0资源服务器的角色,验证Access Token。
    • 自定义Token: 也可以使用自定义的Token,但需要网关每次去查询鉴权服务来验证Token的有效性,是有状态的。

五、 实践示例(以Spring Cloud Gateway + JWT为例)

步骤1:生成与验证JWT

首先,你需要一个认证服务(通常是独立的微服务,如 auth-service),负责用户登录并颁发JWT。

// 伪代码:在 auth-service 中登录成功后生成JWT
@Service
public class AuthService {public String login(String username, String password) {// 1. 验证用户名密码User user = userService.authenticate(username, password);// 2. 生成JWTString token = Jwts.builder().setSubject(user.getId()) // 用户标识.claim("roles", user.getRoles()) // 用户角色.claim("authorities", user.getAuthorities()) // 用户权限.setIssuedAt(new Date()).setExpiration(new Date(System.currentTimeMillis() + 3600000)) // 1小时过期.signWith(SignatureAlgorithm.HS512, secretKey) // 使用密钥签名.compact();return token;}
}
步骤2:网关统一鉴权过滤器

在网关服务中,创建一个全局过滤器 AuthGlobalFilter,实现 GlobalFilter 接口。
过滤器逻辑:

  • 排除登录、注册等白名单路径。
  • 从请求头获取 Authorization。
  • 使用JWT库(如jjwt)验证Token的签名和过期时间。
  • 从JWT的Payload中解析出用户角色和权限。
  • 查询权限规则(可以从数据库或配置中心加载),判断用户权限是否能匹配请求路径+方法。
  • 通过验证,则将用户信息放入请求头,转发请求;否则,直接返回错误响应。

伪代码示例:

@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {@Autowiredprivate JwtUtil jwtUtil; // 一个自定义的JWT工具类@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {ServerHttpRequest request = exchange.getRequest();ServerHttpResponse response = exchange.getResponse();// 1. 判断是否为无需鉴权的白名单路径(如登录、注册、公开API)String path = request.getURI().getPath();if (isExcludePath(path)) {return chain.filter(exchange); // 直接放行}// 2. 提取JWT令牌String token = getTokenFromRequest(request);if (StringUtils.isEmpty(token)) {response.setStatusCode(HttpStatus.UNAUTHORIZED);return response.setComplete(); // 返回401}// 3. 验证并解析JWTClaims claims;try {claims = jwtUtil.parseToken(token); // 验证签名和过期时间} catch (Exception e) {response.setStatusCode(HttpStatus.UNAUTHORIZED);return response.setComplete(); // 令牌无效,返回401}// 4. (可选)权限鉴定 - 这里以基于路径的简单RBAC为例String userRoles = (String) claims.get("roles");if (!hasPermission(userRoles, path, request.getMethodValue())) {response.setStatusCode(HttpStatus.FORBIDDEN);return response.setComplete(); // 权限不足,返回403}// 5. 鉴权通过,将用户信息添加到请求头,传递给下游服务String userId = claims.getSubject();ServerHttpRequest newRequest = request.mutate().header("X-User-Id", userId).header("X-User-Roles", userRoles).build();ServerWebExchange newExchange = exchange.mutate().request(newRequest).build();return chain.filter(newExchange);}private boolean isExcludePath(String path) {// 从配置文件中读取白名单return Arrays.asList("/auth/login", "/auth/register", "/public/**").contains(path);}private String getTokenFromRequest(ServerHttpRequest request) {String authHeader = request.getHeaders().getFirst("Authorization");if (StringUtils.hasText(authHeader) && authHeader.startsWith("Bearer ")) {return authHeader.substring(7);}return null;}private boolean hasPermission(String userRoles, String path, String method) {// 实现你的权限逻辑:例如,查询数据库或缓存,判断该角色是否有权访问此API// 这里可以简化成:检查 userRoles 是否包含访问此路径所需的角色// 更复杂的可以使用像Spring Security的AccessDecisionManagerreturn permissionService.checkPermission(userRoles, path, method);}@Overridepublic int getOrder() {return -100; // 过滤器执行顺序,数字越小优先级越高}
}
步骤3:业务微服务(无需鉴权)

下游的业务微服务(如 user-service)接收到请求后,可以直接从请求头中获取用户信息,并信任该信息。

@RestController
@RequestMapping("/users")
public class UserController {@GetMapping("/{id}")public User getUser(@PathVariable String id, @RequestHeader("X-User-Id") String currentUserId) {// 直接从网关传递的请求头中获取当前用户ID,无需再次解析JWT// 处理业务逻辑...return userService.getUserById(id);}
}
http://www.dtcms.com/a/568709.html

相关文章:

  • 八股已死、场景当立(场景篇-微服务保护篇)
  • 视觉差的网站长沙企业网站排名优化
  • 【代码随想录算法训练营——Day58】图论——117.软件构建、47. 参加科学大会
  • TDengine 字符串函数 CHAR_LENGTH 用户手册
  • Jupyter选择内核时如何找到虚拟环境
  • 【深度强化学习】#6 TRPOPPO:策略优化算法
  • 微雪ESP32-S3-Touch-LCD-2.8-Test编译成功方法esp-idf vscode
  • ASP.NET Core Blazor 核心功能二:Blazor表单和验证
  • 基于大数据的全国降水可视化分析预测系统
  • 阳山网站seo西安官网seo技巧
  • Clip Studio Paint EX v2.0.6 For MacOS – 官方版本+逆向补丁下载,M4芯片Mac实机测试好用
  • 商户查询更新缓存(opsForHash、opsForList、ObjectMapper、@Transactional、@PutMapping)
  • 河北省建设机械会网站首页衡水做网站报价
  • Java 实现 Word 文档文本框操作:添加与删除详解 (使用 Spire.Doc for Java)
  • PDF或Word转图片(多线程+aspose+函数式接口)
  • .docx 和 .doc 是 Microsoft Word 文档的两种主要文件格式
  • RabbitMQ 实战:理解“不公平分发(Unfair Dispatching)”机制
  • 前端缓存技术和使用场景
  • 网站建设价格请咨询兴田德润个人网站建设简历
  • 虚拟机导入报错:行 25: 硬件系列“vmx-21”不受支持。
  • C# TCP 服务器和客户端
  • 【R语言】构建GO、KEGG相关不同物种的R包
  • 缓存三部曲:从线程到分布式
  • LS67211_VC1:48KHz低延时AI降噪USB直播麦克风音频处理器
  • 【C++】分治-快速排序算法习题
  • MySQL第四次作业(索引、视图)
  • Partial Prompt Templates in LangChain
  • 泉州网站平台建设公司网站建设素材图
  • 计算机技术员网站建设怎么网站底部 设计
  • 第50届ICPC亚洲区域赛·成都站,非凸科技持续护航顶尖赛事