说明:文章所用图片除注明来源外,其余均为实测截图;
apisix v2.13.3
在网关中具有多种认证插件,用户可以灵活的选择合适的认证方式。当用户配置有多个认证条件时,是如何通过鉴权的?
一、认证及授权
图1-1 认证及授权插件([3])
1.1、身份认证(Authenticaion)
图1-2 身份认证阶段([3])
阶段:登陆时
用途:识别用户身份
1.2、授权验证 (Authorization)
图1-3 授权阶段([3])
阶段:登陆之后
用途:判断用户是否有权限
1.3、消费者(Consumer)
Consumer[2]是某类服务的消费者
图1-4 消费者
- Client 携带身份认证请求网关
- 网关根据身份认证识别 Client 身份
- 网关执行 Client 身份所属的插件逻辑
图1-5 身份认证执行([2])
定义消费者的字段如下:
字段 |
必选 |
说明 |
username |
是 |
Consumer 名称。 |
plugins |
否 |
该 Consumer 对应的插件配置,它的优先级是最高的:Consumer > Route > Service。 |
接口调用及参数说明[4],消费者资源的唯一标识是username(即所谓的资源ID)
1.4、简单的示例
1.4.1、创建一个消费者
# 创建 Consumer demo ,指定认证插件 key-auth
$ curl http://127.0.0.1:19081/apisix/admin/consumers -H 'X-API-KEY: ebca3b7b5508638c15ba670c8c7963c7' -X PUT -d '
{
"username": "demo",
"plugins": {
"key-auth": {
"key": "auth-one"
}
}
}'
{"action":"set","node":{"key":"\/apisix\/consumers\/demo","value":{"update_time":1692170317,"plugins":{"key-auth":{"key":"auth-one"}},"create_time":1692170317,"username":"demo"}}}
# 查看所有消费者
$ curl http://127.0.0.1:19081/apisix/admin/consumers/ -H 'X-API-KEY: ebca3b7b5508638c15ba670c8c7963c7' -X GET
{"count":1,"action":"get","node":{"nodes":[{"createdIndex":57,"key":"\/apisix\/consumers\/demo","modifiedIndex":57,"value":{"username":"demo","plugins":{"key-auth":{"key":"auth-one"}},"create_time":1692170317,"update_time":1692170317}}],"key":"\/apisix\/consumers","dir":true}}
1.4.2、API开启身份认证
$ curl http://127.0.0.1:19081/apisix/admin/routes/dshia824Ns24k -H 'X-API-KEY: ebca3b7b5508638c15ba670c8c7963c7' -X PUT -d '
{
"uri": "/*",
"name": "book-demo",
"methods": ["GET"],
"plugins": {
"key-auth": {}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:18083": 1
}
},
"status": 1
}'
{"action":"set","node":{"key":"\/apisix\/routes\/dshia824Ns24k","value":{"status":1,"priority":0,"methods":["GET"],"uri":"\/*","plugins":{"key-auth":{"header":"apikey","query":"apikey"}},"name":"book-demo","update_time":1692170741,"create_time":1692170741,"upstream":{"nodes":{"127.0.0.1:18803":1},"scheme":"http","type":"roundrobin","hash_on":"vars","pass_host":"pass"},"id":"dshia824Ns24k"}}}
1.4.2.1、不带认证信息的请求
curl -i 127.0.0.1:19080/api/v1/products/1/reviews
1.4.2.2、带认证信息的请求
curl -i 127.0.0.1:19080/api/v1/products/1/reviews -H "apikey: auth-one"
当API中未限定消费者时,消费者在被创建后默认是具有访问API权限的
1.5、启用多个认证插件的示例
沿用1.4小节的API资源
1.5.1、创建消费者,有多个认证插件
以key-auth、basic-auth为例
# 新增一个消费者,同时配置key-auth、basic-auth认证
$ curl http://127.0.0.1:19081/apisix/admin/consumers -H 'X-API-KEY: ebca3b7b5508638c15ba670c8c7963c7' -X PUT -d '
{
"username": "multiple_auth",
"plugins": {
"key-auth": {
"key": "auth-three"
},
"basic-auth": {
"username": "hello",
"password": "world"
}
}
}'
{"action":"set","node":{"key":"\/apisix\/consumers\/multiple_auth","value":{"update_time":1692174274,"plugins":{"basic-auth":{"password":"world","username":"hello"},"key-auth":{"key":"auth-three"}},"create_time":1692174274,"username":"multiple_auth"}}}
1.5.2、API开启身份认证
curl http://127.0.0.1:19081/apisix/admin/routes/dshia824Ns24k -H 'X-API-KEY: ebca3b7b5508638c15ba670c8c7963c7' -X PUT -d '
{
"uri": "/*",
"name": "book-demo",
"methods": ["GET"],
"plugins": {
"key-auth": {},
"basic-auth": {}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:18083": 1
}
},
"status": 1
}'
{"action":"set","node":{"key":"\/apisix\/routes\/dshia824Ns24k","value":{"status":1,"priority":0,"methods":["GET"],"uri":"\/*","plugins":{"basic-auth":{"hide_credentials":false},"key-auth":{"header":"apikey","query":"apikey"}},"name":"book-demo","update_time":1692174355,"create_time":1692170741,"upstream":{"nodes":{"127.0.0.1:18083":1},"scheme":"http","type":"roundrobin","hash_on":"vars","pass_host":"pass"},"id":"dshia824Ns24k"}}}
1.5.2.1、不带认证token
curl -i 127.0.0.1:19080/api/v1/products/1/reviews
401,认证未通过
1.5.2.2、只带key-auth认证token
curl -i 127.0.0.1:19080/api/v1/products/1/reviews -H "apikey: auth-three"
401,认证未通过,但报错信息来自basic-auth
1.5.2.3、只带basic-auth认证token
curl -i 127.0.0.1:19080/api/v1/products/1/reviews -uhello:world
401,认证未通过,错误信息来自key-auth
1.5.2.4、同时携带key-auth和basic-auth认证token
curl -i 127.0.0.1:19080/api/v1/products/1/reviews -uhello:world -H "apikey: auth-three"
200,通过验证
1.5.2.5、同时携带key-auth和basic-auth认证token,但是认证的配置来自不同的consumer
curl -i 127.0.0.1:19080/api/v1/products/1/reviews -uhello:world -H "apikey: auth-one"
200,通过验证
1.5.3、结果分析(无授权)
- 1.5.2.1-1.5.2.2表明,不同的认证插件在认证时有先后顺序,此场景中可以推断,basic-auth的优先级高于key-auth;查阅apisix源码配置文件,验证了这一点
- 1.5.2.2-1.5.2.4表明,当API启用了多种认证插件时,每种认证都必须通过才能正常调用
- 因此,在设计上如果开放了多种认证策略,那么首先在产品使用时,应该建议用户不要同时启用多重认证,该方式会降低API调用的成功率;
- 若执意开启,则应该进一步提醒用户开启多重认证后的调用逻辑;即1.5.2.5的调用方式,携带所有认证token
- 1.5.2.5-1.5.2.6表明,认证token可以来自不同的消费者
1.6、全局认证与路由级认证配置示例(无授权)
方式:当需要能作用于所有请求的插件配置,可以使用 GlobalRule 来注册一个全局的 Plugin
场景:假定全局认证为basic-auth,路由级认证为key-auth
相关资源:global-rule、consumer、plugin、route
1.6.1、添加一个全局的认证配置
1.6.1.1、添加一个消费者
# 新增一个消费者,配置basic-auth认证
$ curl http://127.0.0.1:19081/apisix/admin/consumers -H 'X-API-KEY: ebca3b7b5508638c15ba670c8c7963c7' -X PUT -d '
{
"username": "global_auth",
"plugins": {
"basic-auth": {
"username": "global",
"password": "helloworld"
}
}
}'
{"action":"set","node":{"key":"\/apisix\/consumers\/global_auth","value":{"update_time":1692176884,"plugins":{"basic-auth":{"password":"helloworld","username":"global"}},"create_time":1692176884,"username":"global_auth"}}}
1.6.1.2、创建一个globalRule
类似在API中的配置方式
# 向 gloabal_rules 资源中添加插件配置
$ curl -X PUT 127.0.0.1:19081/apisix/admin/global_rules/1 \
-H 'Content-Type: application/json' \
-H 'X-API-KEY: ebca3b7b5508638c15ba670c8c7963c7' \
-d '{
"plugins": {
"basic-auth": {}
}
}'
{"action":"set","node":{"key":"\/apisix\/global_rules\/1","value":{"id":"1","plugins":{"basic-auth":{"hide_credentials":false}},"create_time":1692177046,"update_time":1692177046}}}
# 查 global_rules 信息
$ curl -X GET -i 127.0.0.1:19081/apisix/admin/global_rules/1 -H 'X-API-KEY: ebca3b7b5508638c15ba670c8c7963c7'
HTTP/1.1 200 OK
Date: Wed, 16 Aug 2023 09:12:37 GMT
Content-Type: application/json
Transfer-Encoding: chunked
Connection: keep-alive
Server: APISIX/2.13.3
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: *
Access-Control-Max-Age: 3600
{"count":1,"action":"get","node":{"key":"\/apisix\/global_rules\/1","value":{"id":"1","plugins":{"basic-auth":{"hide_credentials":false}},"create_time":1692177046,"update_time":1692177046}}}
1.6.2、创建一个API
为避免API调用冲突,我们将其他API全部下线
# 创建一个新的API
curl http://127.0.0.1:19081/apisix/admin/routes/shdaj723Hwd5w -H 'X-API-KEY: ebca3b7b5508638c15ba670c8c7963c7' -X PUT -d '
{
"uri": "/*",
"name": "gloabal-book-demo",
"methods": ["GET"],
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:18083": 1
}
},
"status": 1
}'
{"action":"set","node":{"key":"\/apisix\/routes\/shdaj723Hwd5w","value":{"status":1,"priority":0,"methods":["GET"],"uri":"\/*","name":"gloabal-book-demo","update_time":1692177435,"upstream":{"nodes":{"127.0.0.1:18083":1},"scheme":"http","type":"roundrobin","hash_on":"vars","pass_host":"pass"},"id":"shdaj723Hwd5w","create_time":1692177435}}}
1.6.2.1、未携带全局认证token
curl -i 127.0.0.1:19080/api/v1/products/1/reviews
1.6.2.2、携带全局认证token
curl -i 127.0.0.1:19080/api/v1/products/1/reviews -uglobal:helloworld
1.6.3、API中启用key-auth认证
在全局认证basic-auth开启的前提下,API中再配置多一个key-auth认证
# 修改API,增加一个key-auth认证
$ curl http://127.0.0.1:19081/apisix/admin/routes/shdaj723Hwd5w -H 'X-API-KEY: ebca3b7b5508638c15ba670c8c7963c7' -X PUT -d '
{
"uri": "/*",
"name": "gloabal-book-demo",
"methods": ["GET"],
"plugins": {
"key-auth": {}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:18083": 1
}
},
"status": 1
}'
{"action":"set","node":{"key":"\/apisix\/routes\/shdaj723Hwd5w","value":{"status":1,"priority":0,"methods":["GET"],"uri":"\/*","plugins":{"key-auth":{"header":"apikey","query":"apikey"}},"name":"gloabal-book-demo","update_time":1692177717,"create_time":1692177435,"upstream":{"nodes":{"127.0.0.1:18083":1},"scheme":"http","type":"roundrobin","hash_on":"vars","pass_host":"pass"},"id":"shdaj723Hwd5w"}}}
1.6.3.1、不携带任何token
curl -i 127.0.0.1:19080/api/v1/products/1/reviews
401,未通过认证,报错信息来自basic-auth
1.6.3.2、仅携带全局认证token
curl -i 127.0.0.1:19080/api/v1/products/1/reviews -uglobal:helloworld
401,未通过认证,报错信息来自auth-auth
1.6.3.3、仅携带API级别的认证token
curl -i 127.0.0.1:19080/api/v1/products/1/reviews -H "apikey: auth-one"
401,未通过认证,报错信息来自basic-auth
1.6.3.4、同时携带全局和API级别的token
curl -i 127.0.0.1:19080/api/v1/products/1/reviews -H "apikey: auth-one" -uglobal:helloworld
200,通过认证
1.6.3.5、同时携带全局和API级别的token,API级别的认证token来自不同消费者
curl -i 127.0.0.1:19080/api/v1/products/1/reviews -H "apikey: auth-two" -uglobal:helloworld
200,通过认证
1.6.4、全局认证使用低优先级、路由级认证使用高优先级
全局使用key-auth、路由级使用basic-auth
# 向 gloabal_rules 资源中添加插件配置,使用低优先级的认证插件
$ curl -X PUT 127.0.0.1:19081/apisix/admin/global_rules/1 \
-H 'Content-Type: application/json' \
-H 'X-API-KEY: ebca3b7b5508638c15ba670c8c7963c7' \
-d '{
"plugins": {
"key-auth": {}
}
}'
{"action":"set","node":{"key":"\/apisix\/global_rules\/1","value":{"id":"1","plugins":{"key-auth":{"header":"apikey","query":"apikey"}},"create_time":1692177046,"update_time":1692178653}}}
# 修改API,使用basic-auth认证
$ curl http://127.0.0.1:19081/apisix/admin/routes/shdaj723Hwd5w -H 'X-API-KEY: ebca3b7b5508638c15ba670c8c7963c7' -X PUT -d '
{
"uri": "/*",
"name": "gloabal-book-demo",
"methods": ["GET"],
"plugins": {
"basic-auth": {}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:18083": 1
}
},
"status": 1
}'
{"action":"set","node":{"key":"\/apisix\/routes\/shdaj723Hwd5w","value":{"status":1,"priority":0,"methods":["GET"],"uri":"\/*","plugins":{"basic-auth":{"hide_credentials":false}},"name":"gloabal-book-demo","update_time":1692178754,"create_time":1692177435,"upstream":{"nodes":{"127.0.0.1:18083":1},"scheme":"http","type":"roundrobin","hash_on":"vars","pass_host":"pass"},"id":"shdaj723Hwd5w"}}}
1.6.4.1、仅携带全局认证token
curl -i 127.0.0.1:19080/api/v1/products/1/reviews -H "apikey:auth-one"
401,认证未通过,缺少basic-auth认证token
1.6.4.2、仅携带API级别token
curl -i 127.0.0.1:19080/api/v1/products/1/reviews -uhello:world
401,认证未通过,缺少key-auth认证token
1.6.4.3、同时携带全局认证和API级别的token
curl -i 127.0.0.1:19080/api/v1/products/1/reviews -uhello:world -H "apikey:auth-one"
认证通过
1.6.4.3、同时携带全局认证和API级别的token,来自不同consumer
curl -i 127.0.0.1:19080/api/v1/products/1/reviews -uhello:world -H "apikey:auth-two"
通过认证
1.6.5 结果分析
1.6.3-1.6.4说明插件执行时,各资源间的优先级为global_rules>route>service;在每个资源中,插件本身也具有执行的优先级;