← 返回题目列表

微服务的认证鉴权为什么要下沉到网关?网关统一鉴权怎么做?

高频 中等 第 3 / 24 题 更新于 2026/08/03
网关鉴权统一认证JWT微服务安全

简化版

**微服务架构下,如果每个服务都自己做「认证 + 鉴权」,会有大量重复代码、逻辑不一致、维护困难——所以主流做法是把「认证鉴权下沉到 API 网关」:网关作为统一入口,先做认证鉴权,通过了才转发给后端服务。**核心流程:① 用户登录,认证服务颁发一个 Token(通常是 JWT)② 后续请求带着 Token 到网关③ 网关统一校验 Token(验签、查是否过期、解析出用户身份),校验通过才放行、转发给后端微服务,不通过直接拦截(返回 401);④ 网关把解析出的用户信息(用户 id、角色等)通过请求头传给后端服务,后端服务信任网关传来的身份、不用再校验 Token(内网信任)。好处:认证鉴权逻辑集中在网关一处(不用每个服务重复写)、后端服务专注业务、安全策略统一。关键点认证(你是谁)适合完全在网关做鉴权(你能不能做这件事)分两层——网关做粗粒度(URL 级别、是否登录),细粒度的业务权限(如「只能改自己的订单」)还得在服务内做。

详细版

网关鉴权 vs 每个服务各自鉴权

各自鉴权(问题):              网关统一鉴权(推荐):
  每个服务自己校验 Token          网关统一校验 Token
  → 重复代码、逻辑可能不一致       → 一处校验,逻辑统一
  → 每个服务都要引安全依赖         → 后端服务专注业务
  → 改鉴权逻辑要改所有服务         → 改一处(网关)

网关统一鉴权流程

1. 登录:POST /login → 认证服务验证账密 → 颁发 JWT
2. 请求:GET /orders  Header: Authorization: Bearer <JWT>

3. 网关:校验 JWT(验签 + 过期 + 解析用户)
     - 校验失败 → 直接返回 401(拦截,不转发)
     - 校验成功 → 解析出 userId、roles

4. 网关转发给订单服务,把用户信息放请求头:
     X-User-Id: 123    X-User-Roles: USER,VIP

5. 订单服务:信任网关传来的用户信息(内网信任),直接用
     不用再校验 JWT(网关已校验)
     做细粒度业务鉴权(如"只能查自己的订单")
// Spring Cloud Gateway 全局过滤器统一鉴权(示意)
@Component
public class AuthGatewayFilter implements GlobalFilter {
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String token = exchange.getRequest().getHeaders().getFirst("Authorization");
        if (!validateJwt(token)) {                  // 校验 JWT
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();  // 拦截,返回 401
        }
        // 校验通过,解析用户信息放请求头,转发
        Claims claims = parseJwt(token);
        ServerHttpRequest request = exchange.getRequest().mutate()
            .header("X-User-Id", claims.getSubject())
            .header("X-User-Roles", claims.get("roles", String.class))
            .build();
        return chain.filter(exchange.mutate().request(request).build());
    }
}

⚠️ 网关统一鉴权有一个必须堵住的安全漏洞:后端服务信任网关传来的用户信息(X-User-Id 等请求头),但如果攻击者能「绕过网关直接访问后端服务」,就能伪造这些请求头冒充任意用户。所以必须保证「后端服务只能通过网关访问、不能被外部直接访问」——通过网络隔离(后端服务在内网、只有网关能访问)、或服务间调用也校验(如内部 Token、mTLS 双向认证)。另外,JWT 的「无状态」是双刃剑:网关校验 JWT 不用查数据库(快、无状态),但也意味着「JWT 签发后无法主动失效」——用户登出、被封禁时,已签发的 JWT 在过期前仍然有效。要支持主动失效,得引入「黑名单」(把要失效的 JWT 存 Redis、网关校验时查黑名单),但这就又变成有状态了(要查 Redis),是无状态和可失效之间的权衡。

完整版教学

一、问题:每个服务各自鉴权的痛点

先理解「为什么要下沉到网关」:

如果每个微服务自己做认证鉴权:
  订单服务、用户服务、商品服务...每个都:
    - 校验 Token(验签、查过期、解析用户)
    - 判断权限
  → 问题:
    ① 重复代码——每个服务都写一遍认证鉴权逻辑
    ② 逻辑可能不一致——不同服务的校验实现有差异、有 bug
    ③ 每个服务都要引安全依赖、配密钥
    ④ 改鉴权逻辑(如换 Token 格式、加校验)要改所有服务
    ⑤ 安全风险分散——一个服务的鉴权漏洞就是入口

微服务的特点让这更糟:
  服务很多——重复 N 次
  独立部署——改一处逻辑要协调所有服务升级

想要的:
  认证鉴权逻辑集中在一处,服务不用重复做
  → 统一入口做鉴权 → API 网关

每个服务各自鉴权的痛点:① 重复代码(每个服务写一遍认证鉴权)、② 逻辑可能不一致(实现有差异有 bug)、③ 每个服务要引安全依赖配密钥、④ 改鉴权逻辑要改所有服务、⑤ 安全风险分散。微服务特点让这更糟(服务多重复 N 次、独立部署改一处要协调所有)。想要的是「认证鉴权集中一处、服务不用重复做」——统一入口做鉴权,即 API 网关。理解「各自鉴权痛点:重复代码/逻辑不一致/每个服务引依赖/改逻辑要改所有服务/风险分散、微服务多且独立部署加剧、需要集中到统一入口网关」,就理解了下沉到网关的动机。

二、认证与鉴权的区别

先分清「认证」和「鉴权」——它们下沉的程度不同:

认证(Authentication,你是谁):
  验证用户身份——账密登录、Token 校验
  → "确认这个请求是谁发的"
  例:校验 JWT 有效、解析出 userId

鉴权(Authorization,你能不能做):
  验证用户有没有权限做某事
  → "确认这个用户能不能访问这个资源/执行这个操作"
  分两种粒度:
    ① 粗粒度:URL/接口级别(这个角色能不能访问 /admin/*)
    ② 细粒度:业务/数据级别(这个用户能不能改这条具体的订单)

下沉到网关的程度:
  认证:完全适合在网关做(统一校验 Token、解析身份)
  鉴权(粗粒度):适合在网关做(URL 级别、角色级别)
    网关配路由规则:"/admin/** 需要 ADMIN 角色"
  鉴权(细粒度):得在服务内做(网关不懂业务)
    "只能改自己的订单"——要查订单归属,是业务逻辑,网关不知道

所以:
  认证 → 网关统一做
  粗粒度鉴权 → 网关做
  细粒度业务鉴权 → 服务内做(网关做不了)

先分清认证(Authentication,你是谁,验证身份/校验 Token)鉴权(Authorization,你能不能做,验证权限)。鉴权分粗粒度(URL/接口级别,角色能否访问 /admin/*)细粒度(业务/数据级别,能否改这条具体订单)下沉程度认证完全适合网关做(统一校验 Token 解析身份)、粗粒度鉴权适合网关做(URL/角色级别)、细粒度业务鉴权得在服务内做(网关不懂业务、不知道订单归属)。理解「认证(你是谁/校验 Token)vs 鉴权(你能不能做/验证权限);鉴权分粗粒度(URL/角色)和细粒度(业务/数据);下沉:认证网关做、粗粒度鉴权网关做、细粒度业务鉴权服务内做」,就理解了认证鉴权的区别和下沉程度。

三、网关统一鉴权的流程

理解网关统一鉴权的完整流程:

完整流程:
  1. 用户登录:
     POST /login(账号密码)→ 认证服务验证 → 颁发 JWT
     JWT 里含:userId、角色、过期时间等(签名保证不可篡改)

  2. 后续请求带 Token:
     GET /orders   Header: Authorization: Bearer <JWT>

  3. 网关拦截、校验 JWT:
     - 验签(用密钥验证签名,防篡改)
     - 查是否过期
     - 解析出用户身份(userId、roles)
     校验失败 → 直接返回 401(拦截,不转发给后端)
     校验成功 → 继续

  4. 网关转发给后端服务,传递用户信息:
     把解析出的 userId、roles 放到请求头
     X-User-Id: 123   X-User-Roles: USER,VIP
     → 转发给订单服务

  5. 后端服务:
     信任网关传来的用户信息(内网信任,网关已校验过)
     直接用 X-User-Id 做业务(不用再校验 JWT)
     做细粒度业务鉴权(如"查自己的订单"用 X-User-Id 过滤)

关键设计:
  - 网关做认证 + 粗粒度鉴权(Token 校验 + URL 级别)
  - 后端服务信任网关的身份传递,专注业务 + 细粒度鉴权
  - 一次校验(网关),后端不重复校验(内网信任)

网关统一鉴权流程:① 登录(认证服务验证颁发 JWT,含 userId/角色/过期时间/签名)→ ② 请求带 TokenAuthorization: Bearer <JWT>)→ ③ 网关校验 JWT(验签+查过期+解析身份,失败返回 401 拦截、成功继续)→ ④ 网关把用户信息放请求头转发X-User-Id/X-User-Roles)→ ⑤ 后端服务信任网关传来的身份(内网信任、不再校验 JWT)、做细粒度业务鉴权。关键:网关做认证+粗粒度鉴权、后端信任网关身份传递专注业务+细粒度鉴权、一次校验后端不重复。理解「流程:登录颁发 JWT→请求带 Token→网关校验(验签/过期/解析,失败 401)→放用户信息请求头转发→后端信任网关身份做业务;网关认证+粗粒度、后端信任+细粒度」,就掌握了统一鉴权流程。

四、安全漏洞:绕过网关

网关鉴权有个必须堵住的漏洞——「绕过网关直接访问后端」:

漏洞:后端服务信任网关传来的请求头(X-User-Id)
  如果攻击者能"绕过网关、直接访问后端服务":
    直接请求订单服务,自己伪造 X-User-Id: 999
    → 后端服务信任这个头 → 冒充用户 999 → 越权!

根本原因:
  后端服务"信任"网关传来的身份(内网信任模型)
  但如果后端能被外部直接访问,这个"信任"就被利用了

解决(必须做):
  ① 网络隔离(最基础):
     后端服务放内网,只有网关能访问、外部访问不到
     → 攻击者到不了后端,只能走网关(网关会校验)
  ② 服务间调用也校验(纵深防御):
     内部服务间也要求 Token 或内部凭证(不裸信任请求头)
     或 mTLS(双向 TLS,服务间互相验证身份)
     → 即使进了内网,也要有合法身份
  ③ 网关到后端加内部标识:
     网关转发时加一个"来自网关"的签名/内部 Token
     后端验证这个标识,确认请求确实来自网关

原则:
  "信任"必须建立在"不可绕过"之上
  网关鉴权 + 后端不可被外部直接访问 = 安全
  只做网关鉴权、后端裸奔 = 有越权漏洞

所以网关统一鉴权,必须配合"后端服务网络隔离"

网关鉴权的漏洞是「绕过网关直接访问后端」——后端信任网关传的 X-User-Id,若攻击者能绕过网关直接访问后端、伪造 X-User-Id: 999,就能冒充用户越权。根本原因是「后端信任网关身份(内网信任),但后端能被外部直接访问时信任被利用」。解决(必须做)① 网络隔离(后端放内网、只有网关能访问、外部访问不到,最基础)、② 服务间调用也校验(内部 Token/mTLS 双向认证、纵深防御)、③ 网关加内部标识(转发加「来自网关」的签名/内部 Token,后端验证)。原则「信任必须建立在不可绕过之上」——网关鉴权 + 后端不可被外部直接访问 = 安全。理解「漏洞:绕过网关直接访问后端伪造 X-User-Id 越权、根本原因后端信任网关身份但能被外部直接访问;解决:网络隔离(后端内网只有网关能访问)+服务间校验(内部 Token/mTLS)+网关加内部标识;信任必须不可绕过」,就掌握了这个关键安全点。

五、JWT 的无状态与失效难题

网关鉴权常用 JWT,理解 JWT 的「无状态」双刃剑:

JWT 的无状态优势:
  JWT 自包含(用户信息 + 签名都在 token 里)
  网关校验 JWT 只需"验签 + 查过期"——不用查数据库/Redis
  → 无状态、快、易水平扩展(网关不用共享 session)

JWT 的失效难题(无状态的代价):
  JWT 一旦签发,在过期前"无法主动失效":
    用户登出 → 但已签发的 JWT 还在过期前有效
    用户被封禁/改密码 → 旧 JWT 仍有效
  → 因为网关只验签+查过期,不查"这个 token 是否被吊销"
  → 无法主动让某个 JWT 失效

解决主动失效(引入状态):
  ① 黑名单:
     要失效的 JWT(如登出的)存 Redis 黑名单
     网关校验时:验签 + 查过期 + 查黑名单(不在黑名单才有效)
     → 但这就变"有状态"了(要查 Redis)
  ② 短过期 + Refresh Token:
     Access Token 过期时间短(如 15 分钟)→ 失效窗口小
     用 Refresh Token 续期(Refresh 可吊销)
     → 平衡无状态和可控性
  ③ 版本号/时间戳:
     用户信息里带版本号,改密码时版本号+1
     JWT 里也存版本号,校验时比对(不匹配则失效)
     → 也要查用户当前版本(有状态)

权衡:
  纯 JWT(无状态):快、易扩展,但不能主动失效
  JWT + 黑名单/短过期:能失效,但引入了状态
  → 根据"是否需要主动失效"权衡

网关常用 JWT,其「无状态」是双刃剑:优势——JWT 自包含(用户信息+签名在 token 里),网关校验只需验签+查过期、不用查数据库(无状态、快、易水平扩展)。失效难题(代价)——JWT 签发后过期前无法主动失效(登出/封禁/改密码后旧 JWT 仍有效,因网关只验签查过期不查是否吊销)。解决主动失效(引入状态)① 黑名单(失效的 JWT 存 Redis、校验时查黑名单,但变有状态)、② 短过期 + Refresh Token(Access Token 短过期缩小失效窗口)、③ 版本号(改密码版本号+1、校验比对)。权衡「纯 JWT 快但不能主动失效 vs JWT+黑名单能失效但有状态」。理解「JWT 无状态优势:自包含、验签查过期不查库、易扩展;失效难题:签发后过期前无法主动失效(登出/封禁仍有效);解决:黑名单(存 Redis 但有状态)/短过期+Refresh/版本号;权衡无状态和可失效」,就掌握了 JWT 的无状态双刃剑。

六、实践与其他方案

总结网关鉴权的实践和其他考量:

实践建议:
  ① 网关做认证(Token 校验)+ 粗粒度鉴权(URL/角色)
  ② 后端服务信任网关身份传递,做细粒度业务鉴权
  ③ 必须做网络隔离(后端不可被外部直接访问)
  ④ 考虑 JWT 失效需求(要主动失效就加黑名单/短过期)
  ⑤ 敏感操作在服务内二次校验(纵深防御)

其他方案/考量:
  ① 认证方式:
     JWT(无状态、自包含,主流)
     或 Session + 网关共享 session(有状态,需 Redis 共享)
     或 OAuth2/OIDC(对接第三方登录、标准协议)
  ② 网关鉴权的实现:
     Spring Cloud Gateway 全局过滤器(GlobalFilter)
     或专门的网关(Kong、APISIX,有认证插件)
     或 Spring Security 在网关层
  ③ 服务网格(Istio):
     可以在 sidecar 层做 mTLS、认证、授权
     → 更细的流量层安全,不改业务代码

核心总结:
  认证鉴权下沉到网关(统一入口一次校验),
  后端信任网关身份(配合网络隔离防绕过),
  细粒度业务鉴权仍在服务内,
  JWT 无状态但失效难(按需加黑名单/短过期)

网关鉴权实践:① 网关做认证+粗粒度鉴权、② 后端信任网关身份做细粒度鉴权、③ 必须网络隔离、④ 考虑 JWT 失效需求、⑤ 敏感操作服务内二次校验。其他方案:认证方式(JWT 无状态主流、Session+共享、OAuth2/OIDC)、实现(Spring Cloud Gateway GlobalFilter、Kong/APISIX 插件、网关层 Spring Security)、服务网格(Istio sidecar 做 mTLS/认证授权、不改业务代码)。理解「实践:网关认证+粗粒度、后端细粒度、网络隔离、JWT 失效需求、敏感操作二次校验;方案:JWT/Session/OAuth2、Spring Cloud Gateway/Kong/Istio」,就掌握了网关鉴权的实践和方案。

记忆钩子:「微服务认证鉴权下沉到网关(每个服务各自鉴权有重复代码/逻辑不一致/改逻辑要改所有);流程:登录颁发 JWT→请求带 Token→网关校验(验签+过期+解析,失败 401 拦截)→把用户信息放请求头(X-User-Id)转发→后端信任网关身份做业务;认证(你是谁)完全网关做、粗粒度鉴权(URL/角色)网关做、细粒度业务鉴权(改自己订单)服务内做;★安全漏洞:绕过网关直接访问后端伪造 X-User-Id 越权→必须网络隔离(后端内网只有网关能访问)+服务间校验(内部 Token/mTLS);JWT 无状态(验签查过期不查库/易扩展)但失效难(签发后无法主动失效,登出仍有效)→黑名单(存 Redis 但有状态)/短过期+Refresh」

七、常见误区与追问

  • 误区:每个微服务自己做认证鉴权最安全。 不好——会导致大量重复代码、逻辑可能不一致(有 bug)、每个服务都要引安全依赖、改鉴权逻辑要改所有服务;主流做法是下沉到网关统一鉴权(一处校验、逻辑统一),后端服务信任网关传来的身份、专注业务。
  • 误区:所有鉴权都能在网关做。 认证(校验 Token)和粗粒度鉴权(URL/角色级别)适合在网关做;但细粒度业务鉴权(如「只能改自己的订单」)网关做不了——它不懂业务、不知道订单归属,这种要在服务内根据业务逻辑做;网关做粗、服务做细。
  • 误区:网关鉴权后,后端服务就绝对安全了。 有个漏洞——后端信任网关传来的 X-User-Id 请求头,如果攻击者能绕过网关直接访问后端、伪造这个头,就能越权;必须配合网络隔离(后端只能通过网关访问、不能被外部直接访问)+ 服务间校验(内部 Token/mTLS)才安全。
  • 误区:JWT 可以随时让它失效。 JWT 是无状态的——网关校验只验签 + 查过期,不查「是否被吊销」,所以 JWT 签发后在过期前无法主动失效(用户登出、被封禁后旧 JWT 仍有效);要支持主动失效得引入黑名单(存 Redis、校验时查)或短过期 + Refresh Token,但这就引入了状态。
  • 追问:为什么要把认证鉴权下沉到网关? 避免每个微服务重复做认证鉴权——如果每个服务自己校验 Token、判断权限,会有大量重复代码、逻辑可能不一致、每个服务都要引安全依赖、改鉴权逻辑要改所有服务;下沉到网关后,网关作为统一入口一次校验,通过了才转发给后端,认证鉴权逻辑集中在一处、后端服务专注业务、安全策略统一、易维护。
  • 追问:网关校验通过后,怎么把用户身份传给后端服务?后端怎么用? 网关解析出用户信息(userId、roles)后,放到请求头(如 X-User-Id、X-User-Roles)转发给后端;后端服务信任网关传来的这些头(内网信任,网关已校验过 Token),直接用 X-User-Id 做业务(不用再校验 JWT)、做细粒度业务鉴权(如用 X-User-Id 过滤只查自己的数据);前提是后端不能被外部直接访问(网络隔离),否则请求头可被伪造。
  • 追问:JWT 的无状态是优点还是缺点? 双刃剑——优点:JWT 自包含(用户信息+签名在 token 里),网关校验只需验签+查过期、不用查数据库/Redis,无状态、快、易水平扩展(网关不用共享 session);缺点:JWT 签发后在过期前无法主动失效(登出、封禁、改密码后旧 JWT 仍有效);要主动失效得引入黑名单或短过期+Refresh Token,但就变有状态了;是「无状态高性能」和「可主动失效」之间的权衡。

八、加强记忆

微服务架构下,把「认证 + 鉴权」下沉到 API 网关做统一鉴权——避免每个服务各自做导致的重复代码、逻辑不一致、改逻辑要改所有服务。核心流程① 用户登录(认证服务颁发 JWT,含 userId/角色/过期/签名)→ ② 请求带 TokenAuthorization: Bearer <JWT>)→ ③ 网关统一校验 JWT验签 + 查过期 + 解析身份,失败返回 401 拦截、成功放行)→ ④ 网关把用户信息放请求头转发X-User-Id/X-User-Roles)→ ⑤ 后端服务信任网关传来的身份(内网信任、不再校验 JWT)、做细粒度业务鉴权。认证鉴权的下沉程度认证(你是谁)完全在网关做、粗粒度鉴权(URL/角色)在网关做、细粒度业务鉴权(改自己的订单)在服务内做(网关不懂业务)。关键安全漏洞:绕过网关直接访问后端伪造 X-User-Id 越权——必须网络隔离(后端只能通过网关访问)+ 服务间校验(内部 Token/mTLS),「信任必须建立在不可绕过之上」。JWT 无状态(验签查过期不查库、快、易扩展)但失效难(签发后过期前无法主动失效,登出仍有效)——要主动失效得加黑名单(存 Redis 但变有状态)或短过期 + Refresh Token。一句话「认证鉴权下沉到网关统一校验(避免每服务重复):登录颁发 JWT→网关校验 JWT(验签+过期+解析,失败 401)→用户信息放请求头转发→后端信任网关身份;认证+粗粒度鉴权网关做、细粒度业务鉴权服务内做;漏洞:绕过网关伪造 X-User-Id 越权→必须网络隔离;JWT 无状态但失效难→黑名单/短过期」。