mirror of
https://github.com/alibaba/higress.git
synced 2026-03-04 00:20:50 +08:00
update plugins doc (#1305)
This commit is contained in:
@@ -1,17 +1,216 @@
|
||||
# 功能说明
|
||||
---
|
||||
title: JWT 认证
|
||||
keywords: [higress,jwt auth]
|
||||
description: JWT 认证插件配置参考
|
||||
---
|
||||
|
||||
## 功能说明
|
||||
`jwt-auth`插件实现了基于JWT(JSON Web Tokens)进行认证鉴权的功能,支持从HTTP请求的URL参数、请求头、Cookie字段解析JWT,同时验证该Token是否有权限访问。
|
||||
|
||||
本插件和`安全能力->认证鉴权`中JWT认证的区别是,额外提供了调用方身份识别的能力,支持对不同调用方配置不同的JWT凭证。
|
||||
|
||||
# 详细说明
|
||||
## 运行属性
|
||||
|
||||
## 1、基于token的认证
|
||||
插件执行阶段:`认证阶段`
|
||||
插件执行优先级:`340`
|
||||
|
||||
### 1.1 简介
|
||||
## 配置字段
|
||||
|
||||
**注意:**
|
||||
|
||||
- 在一个规则里,鉴权配置和认证配置不可同时存在
|
||||
- 对于通过认证鉴权的请求,请求的header会被添加一个`X-Mse-Consumer`字段,用以标识调用者的名称。
|
||||
|
||||
### 认证配置
|
||||
|
||||
| 名称 | 数据类型 | 填写要求 | 默认值 | 描述 |
|
||||
| ----------- | --------------- | ------------------------------------------- | ------ | ----------------------------------------------------------- |
|
||||
| `global_auth` | bool | 选填(**仅实例级别配置**) | - | 只能在实例级别配置,若配置为true,则全局生效认证机制; 若配置为false,则只对做了配置的域名和路由生效认证机制,若不配置则仅当没有域名和路由配置时全局生效(兼容老用户使用习惯)。 |
|
||||
| `consumers` | array of object | 必填 | - | 配置服务的调用者,用于对请求进行认证 |
|
||||
|
||||
`consumers`中每一项的配置字段说明如下:
|
||||
|
||||
| 名称 | 数据类型 | 填写要求 | 默认值 | 描述 |
|
||||
| ----------------------- | ----------------- | -------- | ------------------------------------------------- | ------------------------ |
|
||||
| `name` | string | 必填 | - | 配置该consumer的名称 |
|
||||
| `jwks` | string | 必填 | - | https://www.rfc-editor.org/rfc/rfc7517 指定的json格式字符串,是由验证JWT中签名的公钥(或对称密钥)组成的Json Web Key Set |
|
||||
| `issuer` | string | 必填 | - | JWT的签发者,需要和payload中的iss字段保持一致 |
|
||||
| `claims_to_headers` | array of object | 选填 | - | 抽取JWT的payload中指定字段,设置到指定的请求头中转发给后端 |
|
||||
| `from_headers` | array of object | 选填 | {"name":"Authorization","value_prefix":"Bearer "} | 从指定的请求头中抽取JWT |
|
||||
| `from_params` | array of string | 选填 | access_token | 从指定的URL参数中抽取JWT |
|
||||
| `from_cookies` | array of string | 选填 | - | 从指定的cookie中抽取JWT |
|
||||
| `clock_skew_seconds` | number | 选填 | 60 | 校验JWT的exp和iat字段时允许的时钟偏移量,单位为秒 |
|
||||
| `keep_token` | bool | 选填 | ture | 转发给后端时是否保留JWT |
|
||||
|
||||
**注意:**
|
||||
- 只有当`from_headers`,`from_params`,`from_cookies`均未配置时,才会使用默认值
|
||||
|
||||
`from_headers` 中每一项的配置字段说明如下:
|
||||
|
||||
| 名称 | 数据类型 | 填写要求| 默认值 | 描述 |
|
||||
| ---------------- | --------------- | ------- | ------ | --------------------------------------------------------- |
|
||||
| `name` | string | 必填 | - | 抽取JWT的请求header |
|
||||
| `value_prefix` | string | 必填 | - | 对请求header的value去除此前缀,剩余部分作为JWT |
|
||||
|
||||
`claims_to_headers` 中每一项的配置字段说明如下:
|
||||
|
||||
| 名称 | 数据类型 | 填写要求| 默认值 | 描述 |
|
||||
| ---------------- | --------------- | ------- | ------ | --------------------------------------------------------- |
|
||||
| `claim` | string | 必填 | - | JWT payload中的指定字段,要求必须是字符串或无符号整数类型 |
|
||||
| `header` | string | 必填 | - | 从payload取出字段的值设置到这个请求头中,转发给后端 |
|
||||
| `override` | bool | 选填 | true | true时,存在同名请求头会进行覆盖;false时,追加同名请求头 |
|
||||
|
||||
|
||||
### 鉴权配置(非必需)
|
||||
|
||||
| 名称 | 数据类型 | 填写要求 | 默认值 | 描述 |
|
||||
| ----------- | --------------- | ------------------------------------------- | ------ | ----------------------------------------------------------- |
|
||||
| `allow` | array of string | 选填(**非实例级别配置**) | - | 只能在路由或域名等细粒度规则上配置,对于符合匹配条件的请求,配置允许访问的 consumer,从而实现细粒度的权限控制 |
|
||||
|
||||
## 配置示例
|
||||
|
||||
### 全局配置认证和路由粒度进行鉴权
|
||||
|
||||
注意如果一个JWT能匹配多个`jwks`,则按照配置顺序命中第一个匹配的`consumer`
|
||||
|
||||
在实例级别做如下插件配置:
|
||||
|
||||
```yaml
|
||||
global_auth: false
|
||||
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"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
对 route-a 和 route-b 这两个路由做如下配置:
|
||||
|
||||
```yaml
|
||||
allow:
|
||||
- consumer1
|
||||
```
|
||||
|
||||
对 *.example.com 和 test.com 在这两个域名做如下配置:
|
||||
|
||||
```yaml
|
||||
allow:
|
||||
- consumer2
|
||||
```
|
||||
|
||||
**说明:**
|
||||
|
||||
此例指定的route-a和route-b即在创建网关路由时填写的路由名称,当匹配到这两个路由时,将允许name为consumer1的调用者访问,其他调用者不允许访问。
|
||||
|
||||
此例指定的*.example.com和test.com用于匹配请求的域名,当发现域名匹配时,将允许name为consumer2的调用者访问,其他调用者不被允许访问。
|
||||
|
||||
根据该配置,下列请求可以允许访问:
|
||||
|
||||
假设以下请求会匹配到route-a这条路由
|
||||
|
||||
**将 JWT 设置在 url 参数中**
|
||||
```bash
|
||||
curl 'http://xxx.hello.com/test?access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMyJ9.eyJpc3MiOiJhYmNkIiwic3ViIjoidGVzdCIsImlhdCI6MTY2NTY2MDUyNywiZXhwIjoxODY1NjczODE5fQ.-vBSV0bKeDwQcuS6eeSZN9dLTUnSnZVk8eVCXdooCQ4'
|
||||
```
|
||||
**将 JWT 设置在 http 请求头中**
|
||||
```bash
|
||||
curl http://xxx.hello.com/test -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMyJ9.eyJpc3MiOiJhYmNkIiwic3ViIjoidGVzdCIsImlhdCI6MTY2NTY2MDUyNywiZXhwIjoxODY1NjczODE5fQ.-vBSV0bKeDwQcuS6eeSZN9dLTUnSnZVk8eVCXdooCQ4'
|
||||
```
|
||||
|
||||
认证鉴权通过后,请求的header中会被添加一个`X-Mse-Consumer`字段,在此例中其值为`consumer1`,用以标识调用方的名称
|
||||
|
||||
下列请求将拒绝访问:
|
||||
|
||||
**请求未提供JWT,返回401**
|
||||
```bash
|
||||
curl http://xxx.hello.com/test
|
||||
```
|
||||
|
||||
**根据请求提供的JWT匹配到的调用者无访问权限,返回403**
|
||||
```bash
|
||||
# consumer1不在*.example.com的allow列表里
|
||||
curl 'http://xxx.example.com/test' -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMyJ9.eyJpc3MiOiJhYmNkIiwic3ViIjoidGVzdCIsImlhdCI6MTY2NTY2MDUyNywiZXhwIjoxODY1NjczODE5fQ.-vBSV0bKeDwQcuS6eeSZN9dLTUnSnZVk8eVCXdooCQ4'
|
||||
```
|
||||
|
||||
#### 网关实例级别开启
|
||||
|
||||
以下配置将对网关实例级别开启 JWT Auth 认证,所有请求均需要经过认证后才能访问。
|
||||
|
||||
```yaml
|
||||
global_auth: true
|
||||
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"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 常见错误码说明
|
||||
|
||||
| HTTP 状态码 | 出错信息 | 原因说明 |
|
||||
| ----------- | ---------------------- | -------------------------------------------------------------------------------- |
|
||||
| 401 | Jwt missing | 请求头未提供JWT |
|
||||
| 401 | Jwt expired | JWT已经过期 |
|
||||
| 401 | Jwt verification fails | JWT payload校验失败,如iss不匹配 |
|
||||
| 403 | Access Denied | 无权限访问当前路由 |
|
||||
|
||||
## 详细说明
|
||||
|
||||
### 1、基于token的认证
|
||||
|
||||
#### 1.1 简介
|
||||
|
||||
很多对外开放的API需要识别请求者的身份,并据此判断所请求的资源是否可以返回给请求者。token就是一种用于身份验证的机制,基于这种机制,应用不需要在服务端保留用户的认证信息或者会话信息,可实现无状态、分布式的Web应用授权,为应用的扩展提供了便利。
|
||||
|
||||
### 1.2 流程描述
|
||||
#### 1.2 流程描述
|
||||
|
||||

|
||||
|
||||
@@ -35,13 +234,13 @@
|
||||
|
||||
在这个整个过程中, 网关利用token认证机制,实现了用户使用自己的用户体系对自己API进行授权的能力。下面我们就要介绍网关实现token认证所使用的结构化令牌Json Web Token(JWT)。
|
||||
|
||||
### 1.3 JWT
|
||||
#### 1.3 JWT
|
||||
|
||||
#### 1.3.1 简介
|
||||
##### 1.3.1 简介
|
||||
|
||||
Json Web Toke(JWT),是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准RFC7519。JWT一般可以用作独立的身份验证令牌,可以包含用户标识、用户角色和权限等信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,特别适用于分布式站点的登录场景。
|
||||
|
||||
#### 1.3.2 JWT的构成
|
||||
##### 1.3.2 JWT的构成
|
||||
|
||||
`eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ`
|
||||
|
||||
@@ -119,11 +318,11 @@ var signature = HMACSHA256(encodedString, '$secret');
|
||||
将这三部分用 . 连接成一个完整的字符串,就构成了 1.3.2 节最开始的JWT示例。
|
||||
|
||||
|
||||
#### 1.3.3 时效
|
||||
##### 1.3.3 时效
|
||||
|
||||
网关会验证token中的exp字段,一旦这个字段过期了,网关会认为这个token无效而将请求直接打回。过期时间这个值必须设置。
|
||||
|
||||
#### 1.3.4 JWT的几个特点
|
||||
##### 1.3.4 JWT的几个特点
|
||||
|
||||
1. JWT 默认是不加密,不能将秘密数据写入 JWT。
|
||||
2. JWT 不仅可以用于认证,也可以用于交换信息。有效使用 JWT,可以降低服务器查询数据库的次数。
|
||||
@@ -131,9 +330,9 @@ var signature = HMACSHA256(encodedString, '$secret');
|
||||
4. JWT 本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,JWT 的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证。
|
||||
5. 为了减少盗用,JWT 不应该使用 HTTP 协议明码传输,要使用HTTPS 协议传输。
|
||||
|
||||
## 2、用户系统如何应用JWT插件保护API
|
||||
### 2、用户系统如何应用JWT插件保护API
|
||||
|
||||
### 2.1 生成一对JWK(JSON Web 密钥)
|
||||
#### 2.1 生成一对JWK(JSON Web 密钥)
|
||||
|
||||
**方法一、在线生成:**
|
||||
|
||||
@@ -162,7 +361,7 @@ final String publicKeyString = rsaJsonWebKey.toJson(JsonWebKey.OutputControlLeve
|
||||
final String privateKeyString = rsaJsonWebKey.toJson(JsonWebKey.OutputControlLevel.INCLUDE_PRIVATE);
|
||||
```
|
||||
|
||||
### 2.2 使用JWK中的私钥实现颁发token 的认证服务
|
||||
#### 2.2 使用JWK中的私钥实现颁发token 的认证服务
|
||||
|
||||
需要使用2.1节中在线生成的 Keypair JSON字符串(三个方框内的第一个)或者本地生成的 privateKeyString JSON字符串作为私钥来颁发token,用于授权可信的用户访问受保护的API,具体实现可以参考下方示例。 向客户颁发token的形式由用户根据具体的业务场景决定,可以将颁发token的功能部署到生产环境,配置成普通API后由访问者通过用户名密码获得,也可以直接在本地环境生成token 后,直接拷贝给指定用户使用。
|
||||
|
||||
@@ -216,187 +415,3 @@ public class GenerateJwtDemo {
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# 插件配置说明
|
||||
|
||||
## 配置字段
|
||||
|
||||
| 名称 | 数据类型 | 填写要求 | 默认值 | 描述 |
|
||||
| ----------- | --------------- | ------------------------------------------- | ------ | ----------------------------------------------------------- |
|
||||
| `consumers` | array of object | 必填 | - | 配置服务的调用者,用于对请求进行认证 |
|
||||
| `_rules_` | array of object | 选填 | - | 配置特定路由或域名的访问权限列表,用于对请求进行鉴权 |
|
||||
|
||||
`consumers`中每一项的配置字段说明如下:
|
||||
|
||||
| 名称 | 数据类型 | 填写要求 | 默认值 | 描述 |
|
||||
| ----------------------- | ----------------- | -------- | ------------------------------------------------- | ------------------------ |
|
||||
| `name` | string | 必填 | - | 配置该consumer的名称 |
|
||||
| `jwks` | string | 必填 | - | https://www.rfc-editor.org/rfc/rfc7517 指定的json格式字符串,是由验证JWT中签名的公钥(或对称密钥)组成的Json Web Key Set |
|
||||
| `issuer` | string | 必填 | - | JWT的签发者,需要和payload中的iss字段保持一致 |
|
||||
| `claims_to_headers` | array of object | 选填 | - | 抽取JWT的payload中指定字段,设置到指定的请求头中转发给后端 |
|
||||
| `from_headers` | array of object | 选填 | {"name":"Authorization","value_prefix":"Bearer "} | 从指定的请求头中抽取JWT |
|
||||
| `from_params` | array of string | 选填 | access_token | 从指定的URL参数中抽取JWT |
|
||||
| `from_cookies` | array of string | 选填 | - | 从指定的cookie中抽取JWT |
|
||||
| `clock_skew_seconds` | number | 选填 | 60 | 校验JWT的exp和iat字段时允许的时钟偏移量,单位为秒 |
|
||||
| `keep_token` | bool | 选填 | ture | 转发给后端时是否保留JWT |
|
||||
|
||||
**注意:**
|
||||
- 只有当`from_headers`,`from_params`,`from_cookies`均未配置时,才会使用默认值
|
||||
|
||||
`from_headers` 中每一项的配置字段说明如下:
|
||||
|
||||
| 名称 | 数据类型 | 填写要求| 默认值 | 描述 |
|
||||
| ---------------- | --------------- | ------- | ------ | --------------------------------------------------------- |
|
||||
| `name` | string | 必填 | - | 抽取JWT的请求header |
|
||||
| `value_prefix` | string | 必填 | - | 对请求header的value去除此前缀,剩余部分作为JWT |
|
||||
|
||||
`claims_to_headers` 中每一项的配置字段说明如下:
|
||||
|
||||
| 名称 | 数据类型 | 填写要求| 默认值 | 描述 |
|
||||
| ---------------- | --------------- | ------- | ------ | --------------------------------------------------------- |
|
||||
| `claim` | string | 必填 | - | JWT payload中的指定字段,要求必须是字符串或无符号整数类型 |
|
||||
| `header` | string | 必填 | - | 从payload取出字段的值设置到这个请求头中,转发给后端 |
|
||||
| `override` | bool | 选填 | true | true时,存在同名请求头会进行覆盖;false时,追加同名请求头 |
|
||||
|
||||
|
||||
`_rules_` 中每一项的配置字段说明如下:
|
||||
|
||||
| 名称 | 数据类型 | 填写要求 | 默认值 | 描述 |
|
||||
| ---------------- | --------------- | ------------------------------------------------- | ------ | -------------------------------------------------- |
|
||||
| `_match_route_` | array of string | 选填,`_match_route_`,`_match_domain_`中选填一项 | - | 配置要匹配的路由名称 |
|
||||
| `_match_domain_` | array of string | 选填,`_match_route_`,`_match_domain_`中选填一项 | - | 配置要匹配的域名 |
|
||||
| `allow` | array of string | 必填 | - | 对于符合匹配条件的请求,配置允许访问的consumer名称 |
|
||||
|
||||
**注意:**
|
||||
- 若不配置`_rules_`字段,则默认对当前网关实例的所有路由开启认证;
|
||||
- 对于通过认证鉴权的请求,请求的header会被添加一个`X-Mse-Consumer`字段,用以标识调用者的名称。
|
||||
|
||||
## 配置示例
|
||||
|
||||
### 对特定路由或域名开启
|
||||
|
||||
以下配置将对网关特定路由或域名开启 Jwt Auth 认证和鉴权,注意如果一个JWT能匹配多个`jwks`,则按照配置顺序命中第一个匹配的`consumer`
|
||||
|
||||
```yaml
|
||||
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"
|
||||
}
|
||||
]
|
||||
}
|
||||
# 使用 _rules_ 字段进行细粒度规则配置
|
||||
_rules_:
|
||||
# 规则一:按路由名称匹配生效
|
||||
- _match_route_:
|
||||
- route-a
|
||||
- route-b
|
||||
allow:
|
||||
- consumer1
|
||||
# 规则二:按域名匹配生效
|
||||
- _match_domain_:
|
||||
- "*.example.com"
|
||||
- test.com
|
||||
allow:
|
||||
- consumer2
|
||||
```
|
||||
|
||||
此例 `_match_route_` 中指定的 `route-a` 和 `route-b` 即在创建网关路由时填写的路由名称,当匹配到这两个路由时,将允许`name`为`consumer1`的调用者访问,其他调用者不允许访问;
|
||||
|
||||
此例 `_match_domain_` 中指定的 `*.example.com` 和 `test.com` 用于匹配请求的域名,当发现域名匹配时,将允许`name`为`consumer2`的调用者访问,其他调用者不允许访问。
|
||||
|
||||
#### 根据该配置,下列请求可以允许访问:
|
||||
|
||||
假设以下请求会匹配到route-a这条路由
|
||||
|
||||
**将 JWT 设置在 url 参数中**
|
||||
```bash
|
||||
curl 'http://xxx.hello.com/test?access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMyJ9.eyJpc3MiOiJhYmNkIiwic3ViIjoidGVzdCIsImlhdCI6MTY2NTY2MDUyNywiZXhwIjoxODY1NjczODE5fQ.-vBSV0bKeDwQcuS6eeSZN9dLTUnSnZVk8eVCXdooCQ4'
|
||||
```
|
||||
**将 JWT 设置在 http 请求头中**
|
||||
```bash
|
||||
curl http://xxx.hello.com/test -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMyJ9.eyJpc3MiOiJhYmNkIiwic3ViIjoidGVzdCIsImlhdCI6MTY2NTY2MDUyNywiZXhwIjoxODY1NjczODE5fQ.-vBSV0bKeDwQcuS6eeSZN9dLTUnSnZVk8eVCXdooCQ4'
|
||||
```
|
||||
|
||||
认证鉴权通过后,请求的header中会被添加一个`X-Mse-Consumer`字段,在此例中其值为`consumer1`,用以标识调用方的名称
|
||||
|
||||
#### 下列请求将拒绝访问:
|
||||
|
||||
**请求未提供JWT,返回401**
|
||||
```bash
|
||||
curl http://xxx.hello.com/test
|
||||
```
|
||||
|
||||
**根据请求提供的JWT匹配到的调用者无访问权限,返回403**
|
||||
```bash
|
||||
# consumer1不在*.example.com的allow列表里
|
||||
curl 'http://xxx.example.com/test' -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMyJ9.eyJpc3MiOiJhYmNkIiwic3ViIjoidGVzdCIsImlhdCI6MTY2NTY2MDUyNywiZXhwIjoxODY1NjczODE5fQ.-vBSV0bKeDwQcuS6eeSZN9dLTUnSnZVk8eVCXdooCQ4'
|
||||
```
|
||||
|
||||
### 网关实例级别开启
|
||||
|
||||
以下配置未指定`_rules_`字段,因此将对网关实例级别开启 JWT Auth 认证
|
||||
|
||||
```yaml
|
||||
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"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
# 常见错误码说明
|
||||
|
||||
| HTTP 状态码 | 出错信息 | 原因说明 |
|
||||
| ----------- | ---------------------- | -------------------------------------------------------------------------------- |
|
||||
| 401 | Jwt missing | 请求头未提供JWT |
|
||||
| 401 | Jwt expired | JWT已经过期 |
|
||||
| 401 | Jwt verification fails | JWT payload校验失败,如iss不匹配 |
|
||||
| 403 | Access Denied | 无权限访问当前路由 |
|
||||
|
||||
|
||||
@@ -1,170 +1,306 @@
|
||||
# Description
|
||||
The `jwt-auth` plugin implements authentication and authorization based on JWT (JSON Web Token), supports parsing JWTs from URL parameters, request headers, and Cookie fields from HTTP requests, and verifies whether the token has permission to access.
|
||||
---
|
||||
title: JWT Authentication
|
||||
keywords: [higress,jwt auth]
|
||||
description: JWT Authentication plugin configuration reference
|
||||
---
|
||||
|
||||
The difference between this plugin and the JWT authentication in `Security Capabilities->Authentication and Authorization` is that it provides additional capabilities for identifying the caller's identity, supporting the configuration of different JWT credentials for different callers.
|
||||
## Function Description
|
||||
`jwt-auth` plugin implements authentication and authorization based on JWT (JSON Web Tokens). It supports extracting JWT from HTTP request URL parameters, request headers, and Cookie fields, while verifying whether the Token has the necessary permissions to access the resource.
|
||||
|
||||
# Detailed Description
|
||||
The difference between this plugin and the JWT authentication in `Security Capability -> Authentication and Authorization` is that it additionally provides the capability of identifying the caller's identity, supporting different JWT credentials for different callers.
|
||||
|
||||
## 1. Token-based authentication
|
||||
## Runtime Properties
|
||||
Plugin execution phase: `Authentication Phase`
|
||||
Plugin execution priority: `340`
|
||||
|
||||
### 1.1 Introduction
|
||||
Many open APIs need to identify the identity of the caller and determine whether the requested resource can be returned to the caller based on this identity. Token is a mechanism used for identity verification. Based on this mechanism, the application does not need to retain the user's authentication information or session information on the server, which can realize stateless and distributed web application authorization and provide convenience for application extension.
|
||||
## Configuration Fields
|
||||
**Note:**
|
||||
- In one rule, authentication configuration and authorization configuration cannot coexist.
|
||||
- For requests authenticated through authentication and authorization, the request header will be augmented with an `X-Mse-Consumer` field to identify the caller's name.
|
||||
|
||||
### 1.2 Process Description
|
||||
### Authentication Configuration
|
||||
| Name | Data Type | Requirements | Default Value | Description |
|
||||
| ----------- | --------------- | ---------------------------------------------- | ------------- | ----------------------------------------------------------- |
|
||||
| `global_auth` | bool | Optional (**instance-level configuration only**) | - | Can only be configured at the instance level. If set to true, it will globally enable the authentication mechanism; if set to false, it will only apply to the configured domain names and routes. If not configured, it will only globally take effect when no domain names and routes are configured (to be compatible with old user habits). |
|
||||
| `consumers` | array of object | Required | - | Configure service consumers for request authentication |
|
||||
|
||||

|
||||
The configuration fields for each item in `consumers` are as follows:
|
||||
| Name | Data Type | Requirements | Default Value | Description |
|
||||
| ----------------------- | ------------------ | ------------ | -------------------------------------------------- | ------------------------------- |
|
||||
| `name` | string | Required | - | The name of the consumer |
|
||||
| `jwks` | string | Required | - | JSON format string specified by https://www.rfc-editor.org/rfc/rfc7517, consisting of the public key (or symmetric key) used to verify the JWT signature. |
|
||||
| `issuer` | string | Required | - | The issuer of the JWT, must match the `iss` field in the payload. |
|
||||
| `claims_to_headers` | array of object | Optional | - | Extract the specified fields from the JWT payload and set them in the specified request headers to forward to the backend. |
|
||||
| `from_headers` | array of object | Optional | {"name":"Authorization","value_prefix":"Bearer "} | Extract JWT from the specified request headers. |
|
||||
| `from_params` | array of string | Optional | access_token | Extract JWT from the specified URL parameters. |
|
||||
| `from_cookies` | array of string | Optional | - | Extract JWT from the specified cookies. |
|
||||
| `clock_skew_seconds` | number | Optional | 60 | The allowed clock skew when validating the `exp` and `iat` fields of the JWT, measured in seconds. |
|
||||
| `keep_token` | bool | Optional | true | Whether to retain the JWT when forwarding to the backend. |
|
||||
|
||||
The above figure is the business process sequence diagram when the gateway uses JWT for authentication, and the following we will describe the steps marked in the figure in detail in words:
|
||||
**Note:**
|
||||
- The default values will only be used when `from_headers`, `from_params`, and `from_cookies` are not all configured.
|
||||
The configuration fields for each item in `from_headers` are as follows:
|
||||
| Name | Data Type | Requirements | Default Value | Description |
|
||||
| --------------- | ---------------- | ------------ | ------------- | ----------------------------------------------- |
|
||||
| `name` | string | Required | - | Extract JWT from the request header. |
|
||||
| `value_prefix` | string | Required | - | Remove the prefix from the request header value, with the remaining part serving as the JWT. |
|
||||
|
||||
1. The client initiates an authentication request to the API gateway, usually carrying the end user's username and password in the request;
|
||||
The configuration fields for each item in `claims_to_headers` are as follows:
|
||||
| Name | Data Type | Requirements | Default Value | Description |
|
||||
| --------------- | ---------------- | ------------ | ------------- | --------------------------------------------- |
|
||||
| `claim` | string | Required | - | The specified field in the JWT payload, must be a string or unsigned integer type. |
|
||||
| `header` | string | Required | - | The value of the field extracted from the payload is set to this request header and forwarded to the backend. |
|
||||
| `override` | bool | Optional | true | If true, existing headers with the same name will be overridden; if false, they will be appended. |
|
||||
|
||||
2. The gateway forwards the request directly to the backend service;
|
||||
### Authorization Configuration (Optional)
|
||||
| Name | Data Type | Requirements | Default Value | Description |
|
||||
| ----------- | --------------- | ---------------------------------------------- | ------------- | ----------------------------------------------------------------------------------------------------- |
|
||||
| `allow` | array of string | Optional (**not instance-level configuration**) | - | Can only be configured on fine-grained rules such as routes or domain names, allowing specified consumers to access matching requests for fine-grained permission control. |
|
||||
|
||||
3. The backend service reads the authentication information (such as the username and password) in the request for verification. After the verification is passed, it uses the private key to generate a standard token and returns it to the gateway;
|
||||
## Configuration Examples
|
||||
### Global Configuration for Authentication and Route-Level Authorization
|
||||
Note: If a JWT matches multiple `jwks`, the first matching consumer will be applied according to the configuration order.
|
||||
|
||||
4. The gateway returns the response with the token to the client, and the client needs to cache this token locally;
|
||||
|
||||
5. The client sends a business request to the API gateway, carrying the token in the request;
|
||||
|
||||
6. The gateway uses the public key set by the user to verify the token in the request. After the verification is passed, the request is passed through to the backend service;
|
||||
|
||||
7. The backend service processes the business and responds;
|
||||
|
||||
8. The gateway returns the business response to the client.
|
||||
|
||||
In this entire process, the gateway uses the token authentication mechanism to realize the ability of users to use their own user system to authorize their API. Next, we will introduce the structured token JSON Web Token (JWT) used by the gateway to implement token authentication.
|
||||
|
||||
### 1.3 JWT
|
||||
|
||||
#### 1.3.1 Introduction
|
||||
|
||||
JSON Web Token (JWT) is an open standard RFC7519 based on JSON for executing a type of claim to pass between network applications. JWT can generally be used as an independent identity verification token, which can contain user identification, user roles, and permissions information, making it easier to obtain resources from the resource server, and can also add some other necessary declarative information for other business logic, especially suitable for the login scenario of distributed sites.
|
||||
|
||||
#### 1.3.2 Composition of JWT
|
||||
|
||||
`eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ`
|
||||
|
||||
As shown in the example above, JWT is a string consisting of three parts:
|
||||
|
||||
- Header
|
||||
- Payload
|
||||
- Signature
|
||||
|
||||
**Header**
|
||||
|
||||
The header of the JWT carries two pieces of information:
|
||||
|
||||
- The type of the token, which is JWT
|
||||
- The algorithm used for encryption
|
||||
|
||||
The gateway supports the following encryption algorithms:
|
||||
|
||||
```text
|
||||
ES256, ES384, ES512,
|
||||
HS256, HS384, HS512,
|
||||
RS256, RS384, RS512,
|
||||
PS256, PS384, PS512,
|
||||
EdDSA
|
||||
Configure the plugin at the instance level as follows:
|
||||
```yaml
|
||||
global_auth: false
|
||||
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"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The complete header looks like the following JSON:
|
||||
Configure the following for routes `route-a` and `route-b`:
|
||||
```yaml
|
||||
allow:
|
||||
- consumer1
|
||||
```
|
||||
|
||||
Configure the following for domain names `*.example.com` and `test.com`:
|
||||
```yaml
|
||||
allow:
|
||||
- consumer2
|
||||
```
|
||||
|
||||
**Explanation:**
|
||||
The specified `route-a` and `route-b` refer to the routing names filled in when creating the gateway route. When these two routes are matched, the caller with the name consumer1 will be allowed access, while others will not be permitted.
|
||||
|
||||
The specified `*.example.com` and `test.com` are used to match the request domain names. When a matching domain name is found, the caller with the name consumer2 will be allowed access, while others will not.
|
||||
|
||||
Based on this configuration, the following requests will be allowed:
|
||||
|
||||
Suppose the following request matches the route-a.
|
||||
**Setting the JWT in URL parameters**
|
||||
```bash
|
||||
curl 'http://xxx.hello.com/test?access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMyJ9.eyJpc3MiOiJhYmNkIiwic3ViIjoidGVzdCIsImlhdCI6MTY2NTY2MDUyNywiZXhwIjoxODY1NjczODE5fQ.-vBSV0bKeDwQcuS6eeSZN9dLTUnSnZVk8eVCXdooCQ4'
|
||||
```
|
||||
|
||||
**Setting the JWT in HTTP request headers**
|
||||
```bash
|
||||
curl http://xxx.hello.com/test -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMyJ9.eyJpc3MiOiJhYmNkIiwic3ViIjoidGVzdCIsImlhdCI6MTY2NTY2MDUyNywiZXhwIjoxODY1NjczODE5fQ.-vBSV0bKeDwQcuS6eeSZN9dLTUnSnZVk8eVCXdooCQ4'
|
||||
```
|
||||
|
||||
After successful authentication and authorization, the request's header will include an `X-Mse-Consumer` field, in this example with the value `consumer1`, to identify the caller's name.
|
||||
|
||||
The following requests will be denied:
|
||||
**Request without JWT returns 401**
|
||||
```bash
|
||||
curl http://xxx.hello.com/test
|
||||
```
|
||||
|
||||
**Caller matching from the provided JWT has no access permission, returning 403**
|
||||
```bash
|
||||
# consumer1 is not in the allow list for *.example.com
|
||||
curl 'http://xxx.example.com/test' -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMyJ9.eyJpc3MiOiJhYmNkIiwic3ViIjoidGVzdCIsImlhdCI6MTY2NTY2MDUyNywiZXhwIjoxODY1NjczODE5fQ.-vBSV0bKeDwQcuS6eeSZN9dLTUnSnZVk8eVCXdooCQ4'
|
||||
```
|
||||
|
||||
#### Enable at Gateway Instance Level
|
||||
The following configuration will enable JWT Auth authentication at the instance level, requiring all requests to be authenticated before accessing.
|
||||
```yaml
|
||||
global_auth: true
|
||||
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"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Common Error Codes
|
||||
| HTTP Status Code | Error Message | Reason Description |
|
||||
| ---------------- | ----------------------------- | ---------------------------------------------------------------------------- |
|
||||
| 401 | Jwt missing | The request header did not provide a JWT |
|
||||
| 401 | Jwt expired | The JWT has expired |
|
||||
| 401 | Jwt verification fails | JWT payload verification failed, such as mismatched `iss` |
|
||||
| 403 | Access Denied | No permission to access the current route |
|
||||
|
||||
## Detailed Description
|
||||
### 1. Token-based Authentication
|
||||
#### 1.1 Introduction
|
||||
Many open APIs need to identify the requester's identity and determine whether the requested resource can be returned. A token is a mechanism used for identity verification. With this mechanism, applications do not need to retain user authentication information or session information on the server, allowing for stateless, distributed web application authorization, facilitating application scaling.
|
||||
|
||||
#### 1.2 Process Description
|
||||

|
||||
The above image shows the entire business process sequence diagram for gateway authentication using JWT. Below, we will detail the steps indicated in the diagram:
|
||||
|
||||
1. The client initiates an authentication request to the API gateway, generally carrying the terminal user's username and password.
|
||||
2. The gateway forwards the request directly to the backend service.
|
||||
3. The backend service reads the verification information in the request (such as username and password) for validation. Upon successful verification, it generates a standard token using a private key and returns it to the gateway.
|
||||
4. The gateway returns a response containing the token to the client, who must cache this token locally.
|
||||
5. The client sends a business request to the API gateway, carrying the token in the request.
|
||||
6. The gateway validates the token using the user's set public key. Upon successful validation, it forwards the request to the backend service.
|
||||
7. The backend service processes the business and responds.
|
||||
8. The gateway returns the business response to the client.
|
||||
|
||||
Throughout this process, the gateway utilizes the token authentication mechanism, enabling the user to authorize their API using their user system. Next, we will introduce the structured token used by the gateway for token authentication: JSON Web Token (JWT).
|
||||
|
||||
#### 1.3 JWT
|
||||
##### 1.3.1 Introduction
|
||||
JSON Web Token (JWT) is an open standard (RFC7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. JWT can be used as a stand-alone authentication token, capable of containing user identity, user roles, permissions, and other information, aiding in resource retrieval from resource servers and adding any additional claims required by business logic, particularly suitable for login scenarios for distributed sites.
|
||||
|
||||
##### 1.3.2 JWT Structure
|
||||
`eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ`
|
||||
As shown above, JWT is a string composed of three parts:
|
||||
- Header
|
||||
- Payload
|
||||
- Signature
|
||||
|
||||
**Header**
|
||||
The header of the JWT carries two pieces of information:
|
||||
- Token type, which is JWT
|
||||
- Signing algorithm
|
||||
|
||||
The supported signing algorithms by the gateway are as follows:
|
||||
```text
|
||||
ES256, ES384, ES512,
|
||||
HS256, HS384, HS512,
|
||||
RS256, RS384, RS512,
|
||||
PS256, PS384, PS512,
|
||||
EdDSA
|
||||
```
|
||||
|
||||
The complete header looks like the following JSON:
|
||||
```js
|
||||
{
|
||||
'typ': 'JWT',
|
||||
'alg': 'HS256'
|
||||
}
|
||||
```
|
||||
|
||||
The header is then Base64-encoded (this encoding can be symmetrically decoded), forming the first part:
|
||||
|
||||
`eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9`
|
||||
|
||||
**Payload**
|
||||
|
||||
The payload is where the actual information is stored. The details are defined below:
|
||||
```
|
||||
Then the header is Base64 encoded (this encoding is symmetrically decodable), forming the first part.
|
||||
`eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9`
|
||||
|
||||
**Payload**
|
||||
The payload is where valid information is stored. Its details are defined as follows:
|
||||
```text
|
||||
iss: The issuer of the token. This indicates who created the token and is a string value.
|
||||
sub: The subject identifier. This is the unique identifier for the end user provided by the issuer, and is no longer than 255 ASCII characters, and is case-sensitive within the issuer's scope.
|
||||
aud: The audience(s) of the token, which is an array of case-sensitive strings.
|
||||
exp: The expiration time of the token, after which the token will be invalidated, is an integer declaration representing the Unix timestamp in seconds.
|
||||
iat: The issuance time of the token, is an integer declaration representing the Unix timestamp in seconds.
|
||||
jti: The unique identifier of the token, and the value is unique for every token created by the issuer. It is usually a cryptographically random value to prevent conflicts. This component adds a random entropy that an attacker cannot obtain to the structured token, making it more difficult for the token to be guessed or replayed.
|
||||
```
|
||||
|
||||
Custom fields for a user feature can also be added, such as the example below adding a "name" field for the user's nickname:
|
||||
|
||||
iss: Token issuer. Indicates who created the token, this claim is a string.
|
||||
sub: Subject Identifier, an identifier provided by the issuer for its end users, unique within the issuer's scope, up to 255 ASCII characters, case sensitive.
|
||||
aud: Audience(s), the audience of the token, an array of strings that are case-sensitive.
|
||||
exp: Expiration time, a timestamp of the token's expiration. Tokens expired beyond this time will be invalid. This claim is an integer, representing the number of seconds since January 1, 1970.
|
||||
iat: Issuance time of the token, this claim is an integer, representing the number of seconds since January 1, 1970.
|
||||
jti: Unique identifier for the token, the value of this claim must be unique for each token created by the token issuer to prevent collisions. It is typically a cryptographically random value. This value adds a random entropy component to the structured token that is not accessible to an attacker, helping prevent token guess and replay attacks.
|
||||
```
|
||||
Custom fields necessary for the user system can also be added, for example, the following example adds a nickname `name`:
|
||||
```js
|
||||
{
|
||||
"sub": "1234567890",
|
||||
"name": "John Doe"
|
||||
}
|
||||
```
|
||||
|
||||
The payload is then Base64-encoded, forming the second part of the JWT:
|
||||
|
||||
`JTdCJTBBJTIwJTIwJTIyc3ViJTIyJTNBJTIwJTIyMTIzNDU2Nzg5MCUyMiUyQyUwQSUyMCUyMCUyMm5hbWUlMjIlM0ElMjAlMjJKb2huJTIwRG9lJTIyJTBBJTdE`
|
||||
|
||||
**Signature**
|
||||
|
||||
This part is a string that consists of the Base64-encoded header and Base64-encoded payload concatenated with a period, followed by the encryption of the resulting string using the algorithm specified in the header (where $secret represents the user's private key).
|
||||
```
|
||||
Then encode it in Base64 to obtain the second part of the JWT:
|
||||
`JTdCJTBBJTIwJTIwJTIyc3ViJTIyJTNBJTIwJTIyMTIzNDU2Nzg5MCUyMiUyQyUwQSUyMCUyMCUyMm5hbWUlMjIlM0ElMjAlMjJKb2huJTIwRG9lJTIyJTBBJTdE`
|
||||
|
||||
**Signature**
|
||||
This part requires the Base64-encoded Header and Base64-encoded Payload to be connected by a period, and then encrypted using the signing method declared in the Header (where `$secret` represents the user's private key) to form the third part of the JWT.
|
||||
```js
|
||||
var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload);
|
||||
var signature = HMACSHA256(encodedString, '$secret');
|
||||
```
|
||||
```
|
||||
Connecting these three parts with a period creates a complete string that forms the JWT example at the beginning of section 1.3.2.
|
||||
|
||||
These three parts are then concatenated using periods to form the complete JWT string as shown in the example at the beginning of this section.
|
||||
##### 1.3.3 Validity Period
|
||||
The gateway will validate the `exp` field in the token. Once this field expires, the gateway will consider this token invalid and directly reject the request. The expiration time must be set.
|
||||
|
||||
#### 1.3.3 Time validity
|
||||
##### 1.3.4 Characteristics of JWT
|
||||
1. JWT is not encrypted by default; do not write secret data into JWT.
|
||||
2. JWT can be used for both authentication and information exchange. Effectively using JWT can reduce the number of queries to the database on the server.
|
||||
3. The biggest drawback of JWT is that since the server does not maintain session state, it cannot revoke a token during use or change the permissions of said token. In other words, once a JWT is issued, it will remain valid until expiration, unless the server implements additional logic.
|
||||
4. JWT itself contains authentication information, and once leaked, anyone can gain all permissions of that token. To minimize theft, the validity period of JWT should be set to be relatively short. For some critical permissions, users should be re-authenticated.
|
||||
5. To reduce theft, JWT should not be transmitted in plain text over HTTP but should use HTTPS for transmission.
|
||||
|
||||
The gateway will verify the exp field in the token. Once this field has expired, the gateway will consider the token invalid and reject the request directly. The expiration time value must be set.
|
||||
|
||||
#### 1.3.4 Several Characteristics of JWT
|
||||
|
||||
1. By default, JWT is not encrypted and cannot write secret data into JWT.
|
||||
2. JWT can not only be used for authentication but also for exchanging information. Using JWT effectively can reduce the number of times servers query the database.
|
||||
3. The biggest drawback of JWT is that the server cannot invalidate a token during use, or change the token's permission, because the server does not keep the session state. That is, once JWT is issued, it will always be valid before it expires, unless the server deploys additional logic.
|
||||
4. JWT contains authentication information itself. Once leaked, anyone can obtain all permissions of the token. To reduce theft, the expiration time of JWT should be set relatively short. For some more important permissions, users should be authenticated again when using them.
|
||||
5. To reduce theft, JWT should not be transmitted in plaintext using the HTTP protocol, and the HTTPS protocol should be used for transmission.
|
||||
|
||||
## 2. How to apply the JWT plugin to protect the API of the user system
|
||||
|
||||
### 2.1 Generate a pair of JWK (JSON Web Key)
|
||||
|
||||
**Method 1: Generate online**
|
||||
|
||||
Users can generate the private and public keys used for token generation and verification on this website https://mkjwk.org. The private key is used for the authorization service to issue JWT, and the public key is configured into the JWT plugin for the gateway to verify the signature of the request. Note that the JWKs format configuration used by the gateway requires the public key in the figure below to be placed in the keys structure, such as: `{"keys":[{"kty":"RSA","e":"AQAB",...}]}`
|
||||
|
||||
<img src="https://help-static-aliyun-doc.aliyuncs.com/assets/img/zh-CN/2336348951/p135823.png" style="zoom:50%" />
|
||||
|
||||
**Method 2: Generate locally**
|
||||
|
||||
This article uses a Java example to illustrate, and users of other languages can also find relevant tools to generate key pairs. Create a new Maven project and add the following dependencies:
|
||||
### 2. How User Systems Apply the JWT Plugin to Protect APIs
|
||||
#### 2.1 Generating a Pair of JWKs (JSON Web Keys)
|
||||
**Method 1: Online Generation:**
|
||||
Users can generate the private and public keys used for token generation and verification at this site https://mkjwk.org. The private key is used by the authorization service to issue JWTs, and the public key is configured into the JWT plugin for the gateway to verify requests. Pay attention to the jwks format configuration used by the gateway. In the image below, the Public Key should be placed into the keys structure, for example: `{"keys":[{"kty":"RSA","e":"AQAB",...}]}`
|
||||
<img src="https://help-static-aliyun-doc.aliyuncs.com/assets/img/zh-CN/2336348951/p135823.png" style="zoom:50%" />
|
||||
|
||||
**Method 2: Local Generation:**
|
||||
This article demonstrates using Java; users of other languages can find related tools to generate key pairs. Create a new Maven project and include the following dependency:
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.bitbucket.b_c</groupId>
|
||||
<artifactId>jose4j</artifactId>
|
||||
<version>0.7.0</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
Use the following code to generate a pair of RSA keys:
|
||||
|
||||
```
|
||||
Use the following code to generate a pair of RSA keys:
|
||||
```java
|
||||
RsaJsonWebKey rsaJsonWebKey = RsaJwkGenerator.generateJwk(2048);
|
||||
final String publicKeyString = rsaJsonWebKey.toJson(JsonWebKey.OutputControlLevel.PUBLIC_ONLY);
|
||||
final String privateKeyString = rsaJsonWebKey.toJson(JsonWebKey.OutputControlLevel.INCLUDE_PRIVATE);
|
||||
```
|
||||
|
||||
### 2.2 Implement the token issuance authentication service using the private key in JWK
|
||||
|
||||
The Keypair JSON string generated online in Section 2.1 (the first of the three boxes) or privateKeyString JSON string generated locally needs to be used as the private key to issue tokens for trusted users to access protected APIs. The specific implementation can refer to the following example. The form of issuing tokens to customers is determined by the user according to the specific business scenario. The function of issuing tokens can be deployed in the production environment and configured as a normal API for visitors to obtain through username and password, or tokens can be generated directly in the local environment and copied to designated users for use.
|
||||
```
|
||||
|
||||
#### 2.2 Using the Private Key in JWK to Implement the Token Issuance Authentication Service
|
||||
You will need to use the Keypair JSON string (the first inside the three boxes) generated online in section 2.1 or the locally generated privateKeyString JSON string as the private key to issue tokens for authorizing trusted users to access protected APIs. The specific implementation can refer to the example below. The form of issuing tokens to customers can be determined by the user based on the specific business scenario; it can be deployed in the production environment, configured to be a normal API that visitors can access through username and password, or tokens can be generated locally and directly copied for specified users to use.
|
||||
```java
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PrivateKey;
|
||||
import org.jose4j.json.JsonUtil;
|
||||
import org.jose4j.jwk.RsaJsonWebKey;
|
||||
import org.jose4j.jwk.RsaJwkGenerator;
|
||||
@@ -173,32 +309,29 @@ import org.jose4j.jws.JsonWebSignature;
|
||||
import org.jose4j.jwt.JwtClaims;
|
||||
import org.jose4j.jwt.NumericDate;
|
||||
import org.jose4j.lang.JoseException;
|
||||
|
||||
public class GenerateJwtDemo {
|
||||
public static void main(String[] args) throws JoseException {
|
||||
String keyId = "uniq_key";
|
||||
//Use the Keypair generated in section 2.1 of this article
|
||||
// Use the Keypair generated in section 2.1
|
||||
String privateKeyJson = "{\n"
|
||||
+ " \"kty\": \"RSA\",\n"
|
||||
+ " \"d\": "
|
||||
+
|
||||
"\"O9MJSOgcjjiVMNJ4jmBAh0mRHF_TlaVva70Imghtlgwxl8BLfcf1S8ueN1PD7xV6Cnq8YenSKsfiNOhC6yZ_fjW1syn5raWfj68eR7cjHWjLOvKjwVY33GBPNOvspNhVAFzeqfWneRTBbga53Agb6jjN0SUcZdJgnelzz5JNdOGaLzhacjH6YPJKpbuzCQYPkWtoZHDqWTzCSb4mJ3n0NRTsWy7Pm8LwG_Fd3pACl7JIY38IanPQDLoighFfo-Lriv5z3IdlhwbPnx0tk9sBwQBTRdZ8JkqqYkxUiB06phwr7mAnKEpQJ6HvhZBQ1cCnYZ_nIlrX9-I7qomrlE1UoQ\",\n"
|
||||
+ " \"d\": \"O9MJSOgcjjiVMNJ4jmBAh0mRHF_TlaVva70Imghtlgwxl8BLfcf1S8ueN1PD7xV6Cnq8YenSKsfiNOhC6yZ_fjW1syn5raWfj68eR7cjHWjLOvKjwVY33GBPNOvspNhVAFzeqfWneRTBbga53Agb6jjN0SUcZdJgnelzz5JNdOGaLzhacjH6YPJKpbuzCQYPkWtoZHDqWTzCSb4mJ3n0NRTsWy7Pm8LwG_Fd3pACl7JIY38IanPQDLoighFfo-Lriv5z3IdlhwbPnx0tk9sBwQBTRdZ8JkqqYkxUiB06phwr7mAnKEpQJ6HvhZBQ1cCnYZ_nIlrX9-I7qomrlE1UoQ\",\n"
|
||||
+ " \"e\": \"AQAB\",\n"
|
||||
+ " \"alg\": \"RS256\",\n"
|
||||
+ " \"n\": \"vCuB8MgwPZfziMSytEbBoOEwxsG7XI3MaVMoocziP4SjzU4IuWuE_DodbOHQwb_thUru57_Efe"
|
||||
+
|
||||
"--sfATHEa0Odv5ny3QbByqsvjyeHk6ZE4mSAV9BsHYa6GWAgEZtnDceeeDc0y76utXK2XHhC1Pysi2KG8KAzqDa099Yh7s31AyoueoMnrYTmWfEyDsQL_OAIiwgXakkS5U8QyXmWicCwXntDzkIMh8MjfPskesyli0XQD1AmCXVV3h2Opm1Amx0ggSOOiINUR5YRD6mKo49_cN-nrJWjtwSouqDdxHYP-4c7epuTcdS6kQHiQERBd1ejdpAxV4c0t0FHF7MOy9kw\"\n"
|
||||
+ " \"n\": \"vCuB8MgwPZfziMSytEbBoOEwxsG7XI3MaVMoocziP4SjzU4IuWuE_DodbOHQwb_thUru57_Efe--sfATHEa0Odv5ny3QbByqsvjyeHk6ZE4mSAV9BsHYa6GWAgEZtnDceeeDc0y76utXK2XHhC1Pysi2KG8KAzqDa099Yh7s31AyoueoMnrYTmWfEyDsQL_OAIiwgXakkS5U8QyXmWicCwXntDzkIMh8MjfPskesyli0XQD1AmCXVV3h2Opm1Amx0ggSOOiINUR5YRD6mKo49_cN-nrJWjtwSouqDdxHYP-4c7epuTcdS6kQHiQERBd1ejdpAxV4c0t0FHF7MOy9kw\"\n"
|
||||
+ "}";
|
||||
JwtClaims claims = new JwtClaims();
|
||||
claims.setGeneratedJwtId();
|
||||
claims.setIssuedAtToNow();
|
||||
//Expiration time must be set
|
||||
// Expiration time must be set
|
||||
NumericDate date = NumericDate.now();
|
||||
date.addSeconds(120*60);
|
||||
claims.setExpirationTime(date);
|
||||
claims.setNotBeforeMinutesInThePast(1);
|
||||
claims.setSubject("YOUR_SUBJECT");
|
||||
claims.setAudience("YOUR_AUDIENCE");
|
||||
//Add custom parameters, use String type for all values
|
||||
// Add custom parameters, all values should be String type
|
||||
claims.setClaim("userId", "1213234");
|
||||
claims.setClaim("email", "userEmail@youapp.com");
|
||||
JsonWebSignature jws = new JsonWebSignature();
|
||||
@@ -206,194 +339,9 @@ public class GenerateJwtDemo {
|
||||
jws.setKeyIdHeaderValue(keyId);
|
||||
jws.setPayload(claims.toJson());
|
||||
PrivateKey privateKey = new RsaJsonWebKey(JsonUtil.parseJson(privateKeyJson)).getPrivateKey();
|
||||
|
||||
jws.setKey(privateKey);
|
||||
String jwtResult = jws.getCompactSerialization();
|
||||
System.out.println("Generate Json Web token , result is " + jwtResult);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# Plugin Configuration Guide
|
||||
|
||||
## Configuration Fields
|
||||
|
||||
| Name | Data Type | Required | Default | Description |
|
||||
| ----------- | --------------- | ------------------------------------------- | ------ | ----------------------------------------------------------- |
|
||||
| `consumers` | array of object | Yes | - | Configures callers of the service for authenticating requests |
|
||||
| `_rules_` | array of object | Optional | - | Configures access control lists for specific routes or domains for authorizing requests |
|
||||
|
||||
The configuration field descriptions for each item in consumers are as follows:
|
||||
|
||||
| Name | Data Type | Required | Default | Description|
|
||||
| ----------------------- | ----------------- | -------- | ------------------------------------------------- | ------------------------ |
|
||||
| `name` | string | Yes | - | Configures the name of this consumer |
|
||||
| `jwks` | string | Yes | - | Specifies a JSON Web Key Set, as defined in https://www.rfc-editor.org/rfc/rfc7517, consisting of public keys (or symmetric keys) used to verify the signature of JWT |
|
||||
| `issuer` | string | Yes | - | The issuer of the JWT, which should be consistent with the iss field in the payload |
|
||||
| `claims_to_headers` | array of object | Optional | - | Extracts the specified fields from the JWT's payload and sets them to the specified request headers for forwarding to the backend |
|
||||
| `from_headers` | array of object | Optional | {"name":"Authorization","value_prefix":"Bearer "} | Extracts the JWT from the specified request headers |
|
||||
| `from_params` | array of string | Optional | access_token | Extracts the JWT from the specified URL parameters |
|
||||
| `from_cookies` | array of string | Optional | - | Extracts the JWT from the specified cookie(s) |
|
||||
| `clock_skew_seconds` | number | Optional | 60 | The amount of clock skew, in seconds, that is allowed when verifying the exp and iat fields of the JWT |
|
||||
| `keep_token` | bool | Optional | ture | Whether to keep the JWT when forwarding it to the backend |
|
||||
|
||||
**Note:**
|
||||
|
||||
- The default value is used only if neither `from_headers`, `from_params`, nor `from_cookies` are configured.
|
||||
|
||||
The configuration field descriptions for each item in `from_headers` are as follows:
|
||||
|
||||
| Name | Data Type | Required| Default | Description |
|
||||
| ---------------- | --------------- | ------- | ------ | --------------------------------------------------------- |
|
||||
| `name` | string | Yes | - | Specifies the request header to extract the JWT from |
|
||||
| `value_prefix` | string | Yes | - | Removes the specified prefix from the request header's value, leaving the rest as the JWT |
|
||||
|
||||
The configuration field descriptions for each item in `claims_to_headers` are as follows:
|
||||
|
||||
| Name | Data Type | Required| Default | Description |
|
||||
| ---------------- | --------------- | ------- | ------ | --------------------------------------------------------- |
|
||||
| `claim` | string | Yes | - | The name of the field in the JWT payload, which must be a string or unsigned integer |
|
||||
| `header` | string | Yes | - | Sets the value of the specified request header to the value of the specified field in the payload, for forwarding to the backend |
|
||||
| `override` | bool | Optional | true | If true, overrides an existing header with the same name; if false, appends the header to the existing headers |
|
||||
|
||||
The configuration field descriptions for each item in `_rules_` are as follows:
|
||||
|
||||
| Name | Data Type | Required| Default | Description |
|
||||
| ---------------- | --------------- | ------------------------------------------------- | ------ | -------------------------------------------------- |
|
||||
| `_match_route_` | array of string | Optional, select either `_match_route_` or `_match_domain_` | - | Configures the route names to match|
|
||||
| `_match_domain_` | array of string | Optional, select either `_match_route_` or `_match_domain_` | - | Configures the domains to match |
|
||||
| `allow` | array of string | Required | - | Configures the consumer names allowed to access the matched requests |
|
||||
|
||||
**Note:**
|
||||
- If the `_rules_` field is not configured, authentication and authorization are enabled for all routes of the current gateway instance by default;
|
||||
- For authenticated and authorized requests, a `X-Mse-Consumer` field is added to the request header to identify the caller's name.
|
||||
|
||||
## Configuration Example
|
||||
|
||||
### Enable for Specific Routes or Domains
|
||||
|
||||
The following configuration enables Jwt Auth authentication and authorization for specific routes or domains of the gateway. If a JWT can match multiple `jwks`, the first matching `consumer` is hit according to the configuration order.
|
||||
|
||||
```yaml
|
||||
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"
|
||||
}
|
||||
]
|
||||
}
|
||||
# Use the _rules_ field for fine-grained rule configuration
|
||||
_rules_:
|
||||
# Rule 1: Effective when matched by route name
|
||||
- _match_route_:
|
||||
- route-a
|
||||
- route-b
|
||||
allow:
|
||||
- consumer1
|
||||
# Rule 2: Effective when matched by domain name
|
||||
- _match_domain_:
|
||||
- "*.example.com"
|
||||
- test.com
|
||||
allow:
|
||||
- consumer2
|
||||
```
|
||||
|
||||
In this example, the `route-a` and `route-b` specified in `_match_route_` are the names of the routes filled in when creating the gateway route. When these two routes are matched, access will be allowed for the caller with the `name` of `consumer1`, and other callers will not be allowed to access.
|
||||
|
||||
The `*.example.com` and `test.com` specified in `_match_domain_` are used to match the domain names of the requests. When a domain name match is found, access will be allowed for the caller with the `name` of `consumer2`, and other callers will not be allowed to access.
|
||||
|
||||
#### According to this configuration, the following requests are allowed:
|
||||
|
||||
Assuming the following requests will match the route-a route:
|
||||
|
||||
**JWT is set in URL parameter**
|
||||
```bash
|
||||
curl 'http://xxx.hello.com/test?access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMyJ9.eyJpc3MiOiJhYmNkIiwic3ViIjoidGVzdCIsImlhdCI6MTY2NTY2MDUyNywiZXhwIjoxODY1NjczODE5fQ.-vBSV0bKeDwQcuS6eeSZN9dLTUnSnZVk8eVCXdooCQ4'
|
||||
```
|
||||
|
||||
**JWT is set in HTTP request header**
|
||||
```bash
|
||||
curl http://xxx.hello.com/test -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMyJ9.eyJpc3MiOiJhYmNkIiwic3ViIjoidGVzdCIsImlhdCI6MTY2NTY2MDUyNywiZXhwIjoxODY1NjczODE5fQ.-vBSV0bKeDwQcuS6eeSZN9dLTUnSnZVk8eVCXdooCQ4'
|
||||
```
|
||||
|
||||
After authentication and authorization, a `X-Mse-Consumer` field will be added in the request header with a value of `consumer1` in this example, to identify the name of the caller.
|
||||
|
||||
#### The following requests will be denied:
|
||||
|
||||
**Request without JWT provided, returns 401**
|
||||
```bash
|
||||
curl http://xxx.hello.com/test
|
||||
```
|
||||
|
||||
**The consumer matched by the provided JWT in the request does not have access, returns 403**
|
||||
```bash
|
||||
# consumer1 is not in the allow list of *.example.com
|
||||
curl 'http://xxx.example.com/test' -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMyJ9.eyJpc3MiOiJhYmNkIiwic3ViIjoidGVzdCIsImlhdCI6MTY2NTY2MDUyNywiZXhwIjoxODY1NjczODE5fQ.-vBSV0bKeDwQcuS6eeSZN9dLTUnSnZVk8eVCXdooCQ4'
|
||||
```
|
||||
|
||||
### Enabling at Gateway Instance Level
|
||||
|
||||
The following configuration does not specify the `_rules_` field, so JWT authentication will be enabled at the gateway instance level:
|
||||
|
||||
```yaml
|
||||
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"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
# Common Error Codes
|
||||
|
||||
| HTTP Status Code | Error Message | Reason Description|
|
||||
|------------------| ---------------------- | -------------------------------------------------------------------------------- |
|
||||
| 401 | JWT missing | The JWT is not provided in the request header. |
|
||||
| 401 | JWT expired | The JWT has expired. |
|
||||
| 401 | JWT verification fails | The JWT payload verification failed, such as the iss mismatch. |
|
||||
| 403 | Access denied | Access to the current route is denied. |
|
||||
|
||||
Reference in New Issue
Block a user