Bootstrap

微服务网关的认证管理;原理与实践

API安全认证是网关的最重要能力

API 网关为了保护对外提供的API,避免诸如恶意访问、未授权访问、应用漏洞及黑客攻击等导致的数据和资产损失,采用API网关的认证机制显得十分必要。

这种认证机制通过基于token的身份验证来实现,它允许应用程序在不保留用户认证信息或会话信息的情况下识别请求者的身份,从而判断所请求的资源是否可以返回给请求者。

API网关常见认证方式说明与解析

API密钥:适用于需要简单快速实现访问控制的场景。优势是易于实施和管理,劣势是安全性较低,容易被滥用或泄露。

OAuth 2.0:适合需要第三方授权访问的应用场景。优点在于提供了灵活的安全机制和良好的用户体验,缺点是配置相对复杂,学习成本较高。

JWT(JSON Web Token):适用于分布式系统中跨域认证。其主要优势为减轻服务器负担、提高响应速度;但令牌一旦签发,在过期前无法撤销成为其一大缺点。

Basic Auth:最简单的HTTP身份验证方法之一,适合于非敏感信息传输。它实现起来非常简单快捷,但由于以明文形式传输用户名密码,因此安全性较差。

OpenID Connect:基于OAuth 2.0协议构建的身份验证层,适合单点登录(SSO)。能够简化用户登录流程并增强安全性,不过对于小型项目来说可能显得过于重量级。

这里面最常用的还是JWT和OAuth ,后面以JWT为例,说明具体的网关认证流程与原理

JWT 认证方式来说明网关认证的流程与原理

JWT (Json Web Token) 是一种开放标准 (RFC 7519),用于在网络应用环境间安全地将信息作为 JSON 对象传输。它通常用于身份验证和信息交换。以下是以JWT认证为例的网关认证基本原理及详细步骤。

1. 客户端向 API 网关发起认证请求
  • 客户端API 网关 发起一个认证请求,这个请求中一般会携带终端用户的用户名和密码。
  • 请求示例:
curl -X POST http://api.example.com/auth -d 'username=johndoe&password=secret'
2. 网关将请求转发给后端服务
  • 网关收到请求后,将其直接转发给后端服务进行用户身份验证。
3. 后端服务验证用户身份并生成 JWT
  • 后端服务读取请求中的验证信息(如用户名、密码),通过数据库或其他方式验证这些信息是否正确。
  • 如果验证通过,后端服务使用私钥生成一个标准的 JWT,并返回给网关
  • 生成 JWT 的示例代码:
JwtClaims claims = new JwtClaims();
claims.setGeneratedJwtId();
claims.setIssuedAtToNow();
claims.setExpirationTime(NumericDate.now().addSeconds(3600)); // 设置过期时间为1小时
claims.setSubject("johndoe");
JsonWebSignature jws = new JsonWebSignature();
jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256);
jws.setPayload(claims.toJson());
PrivateKey privateKey = ...; // 使用从 JWK 中获取的私钥
jws.setKey(privateKey);
String jwt = jws.getCompactSerialization();
4. 网关将 JWT 返回给客户端
  • 网关将携带 JWT 的响应返回给客户端,客户端需要将这个 JWT 缓存到本地(例如存储在浏览器的 localStorage 或 sessionStorage 中)。
  • 响应示例:
{
  "token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJKb2huIERvZSIsImlhdCI6MTYyOTIzMjEwOSwiZXhwIjoxNjI5MjMyNzA5fQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
}
5. 客户端向 API 罗盘发送业务请求,请求中携带 JWT
  • 客户端需要访问受保护的资源时,会在请求头中添加 JWT。
  • 请求示例:
curl -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJKb2huIERvZSIsImlhdCI6MTYyOTIzMjEwOSwiZXhwIjoxNjI5MjMyNzA5fQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c" http://api.example.com/protected-resource
6. 网关验证 JWT 并转发请求
  • 网关接收到请求后,使用配置的公钥对请求中的 JWT 进行验证。
  • 验证过程包括检查 JWT 的签名、过期时间等字段。
  • 如果验证通过,网关将请求透传给后端服务;如果验证失败,则返回相应的错误码(如 401 Unauthorized)。
7. 后端服务处理业务请求并返回响应
  • 后端服务处理完业务逻辑后,返回响应给网关
8. 网关将业务响应返回给客户端
  • 网关后端服务的响应返回给客户端

通过上述步骤,网关利用 JWT 实现了无状态的身份验证机制,确保只有经过认证的用户才能访问受保护的资源。这种机制不仅简化了身份验证的过程,还提高了系统的可扩展性和安全性。

下面我们用Higress来具体看看,怎么通过简单配置的方式实现JWT 认证。

Higress 简单介绍

Higress 是一个基于 Envoy 和 Istio 构建的云原生 API 网关,实现了流量网关、微服务网关和安全网关三合一的高集成能力。它能够支持 Dubbo、Nacos、Sentinel 等微服务技术栈,并通过配置即可快速方便地支持多种安全认证方式,极大地简化了部署和运维成本。

Higress JWT认证配置详解

要基于Higress实现JWT认证,我们需要通过详细的配置来确保认证机制能够正确地工作。这包括全局配置、消费者配置以及对特定路由或域名开启JWT认证的具体步骤。以下将按照配置字段说明和示例配置来进行详细介绍。

全局配置

首先,在全局配置中,需要定义consumersglobal_auth两个主要参数。

  • consumers:这是一个数组,用于定义服务调用者的信息,每一个消费者都需要配置其名称(name)、JSON Web Key Set(jwks)及签发者(issuer)。此外,还可以根据需求设置其他如claims_to_headersfrom_headers等。
  • global_auth:该布尔值决定了JWT认证是否全局生效。若为true,则所有请求均需通过认证;若为false,只有明确设置了allow列表的路由或域名才需要认证。

配置示例

consumers:
  - name: consumer1
    issuer: abcd
    jwks: |
      {
        "keys": [
          {
            "kty": "oct",
            "kid": "123",
            "k": "hM0k3AbXBPpKOGg__Ql2Obcq7s60myWDpbHXzgKUQdYo7YCRp0gUqkCnbGSvZ2rGEl4YFkKqIqW7mTHdj-bcqXpNr-NOznEyMpVPOIlqG_NWVC3dydBgcsIZIdD-MR2AQceEaxriPA_VmiUCwfwL2Bhs6_i7eolXoY11EapLQtutz0BV6ZxQQ4dYUmct--7PLNb4BWJyQeWu0QfbIthnvhYllyl2dgeLTEJT58wzFz5HeNMNz8ohY5K0XaKAe5cepryqoXLhA-V-O1OjSG8lCNdKS09OY6O0fkyweKEtuDfien5tHHSsHXoAxYEHPFcSRL4bFPLZ0orTt1_4zpyfew",
            "alg": "HS256"
          }
        ]
      }
  - name: consumer2
    issuer: abc
    jwks: |
      {
        "keys": [
          {
            "kty": "RSA",
            "e": "AQAB",
            "use": "sig",
            "kid": "123",
            "alg": "RS256",
            "n": "i0B67f1jggT9QJlZ_8QL9QQ56LfurrqDhpuu8BxtVcfxrYmaXaCtqTn7OfCuca7cGHdrJIjq99rz890NmYFZuvhaZ-LMt2iyiSb9LZJAeJmHf7ecguXS_-4x3hvbsrgUDi9tlg7xxbqGYcrco3anmalAFxsbswtu2PAXLtTnUo6aYwZsWA6ksq4FL3-anPNL5oZUgIp3HGyhhLTLdlQcC83jzxbguOim-0OEz-N4fniTYRivK7MlibHKrJfO3xa_6whBS07HW4Ydc37ZN3Rx9Ov3ZyV0idFblU519nUdqp_inXj1eEpynlxH60Ys_aTU2POGZh_25KXGdF_ZC_MSRw"
          }
        ]
      }

global_auth: false
域名和路由级配置

对于特定的路由或域名,可以通过allow字段指定允许访问的consumer名单。如果全局认证被关闭(即global_auth: false),那么仅这些特定路径上的请求才会进行认证检查。

配置示例

# 对 route-a 和 route-b 这两个路由做如下配置:
route-a:
  allow:
    - consumer1
route-b:
  allow:
    - consumer1

# 对 *.example.com 和 test.com 在这两个域名做如下配置:
*.example.com:
  allow:
    - consumer2
test.com:
  allow:
    - consumer2
注意事项
  • 只有当from_headersfrom_paramsfrom_cookies均未配置时,系统会使用默认值从HTTP头部获取JWT。
  • 认证成功后,请求的header中会被添加一个X-Mse-Consumer字段,标识调用方的名称。
  • 如果请求中未提供有效的JWT或者提供的JWT不满足权限要求,则分别返回401或403状态码。

通过上述配置,你可以在Higress上启用JWT认证,并根据实际需要灵活调整具体的认证规则与范围。

Higress的简易安装指南

根据我了解的信息中提供的信息,可以使用Docker来快速地在本地单机上部署和运行Higress。这种部署方式非常适合个人开发者进行学习或者搭建简易站点使用。

前提条件
确保您的机器已经安装了Docker。如果尚未安装,请访问Docker官方文档按照指引完成安装过程。

部署步骤

  1. 创建一个用于存放Higress相关文件的工作目录。
mkdir higress
  1. 启动Higress容器。此命令会启动一个包含Higress及其所有必要组件的容器,并将主机上的8001、8080以及8443端口映射到容器内的相应端口。
docker run -d --rm --name higress-ai -v ./higress:/data \
        -p 8001:8001 -p 8080:8080 -p 8443:8443  \
        higress-registry.cn-hangzhou.cr.aliyuncs.com/higress/all-in-one:latest

这里指定使用的镜像是higress-registry.cn-hangzhou.cr.aliyuncs.com/higress/all-in-one:latest,它包含了运行Higress所需的所有组件。同时通过-v选项将当前目录下的higress子目录挂载到容器内部,以便于持久化配置数据等信息。

监听端口说明

  • 8001 端口:Higress UI 控制台入口。
  • 8080 端口:网关 HTTP 协议入口。
  • 8443 端口:网关 HTTPS 协议入口。

完成上述步骤后,您就成功地在本地环境中部署了一个Higress实例。接下来可以通过浏览器访问http://127.0.0.1:8001打开Higress控制台来进行进一步的配置工作。

注意,在首次访问控制台时需要先初始化管理员账号,之后便可以登录并开始配置服务来源及路由规则等。

以上就是基于Docker实现Higress单机版的完整安装流程。

;