Skip to content

Commit de3c95d

Browse files
authored
feature: support consumer bind plugins. (#544)
* feature: saved consumer plugin information. * feature: supported to merge plugin with consumer and route.
1 parent 6b4d018 commit de3c95d

File tree

19 files changed

+473
-145
lines changed

19 files changed

+473
-145
lines changed

doc/architecture-design-cn.md

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -369,20 +369,72 @@ APISIX 区别于其他 API 网关的一大特点是允许用户选择不同 Rout
369369

370370
如上图所示,作为 API 网关,需要知道 API Consumer(消费方)具体是谁,这样就可以对不同 API Consumer 配置不同规则。
371371

372+
|字段|必选|说明|
373+
|---|----|----|
374+
|username||Consumer 名称。|
375+
|plugins||该 Consumer 对应的插件配置,它的优先级是最高的:Consumer > Route > Service。对于具体插件配置,可以参考 [Plugins](#plugin) 章节。|
376+
372377
在 APISIX 中,识别 Consumer 的过程如下图:
373378

374379
<img src="./images/consumer-internal.png" width="50%" height="50%">
375380

376-
1. 授权认证:比如有 [key-auth](doc/plugins/key-auth.md)[JWT](doc/plugins/jwt-auth-cn.md) 等。
381+
1. 授权认证:比如有 [key-auth](./plugins/key-auth.md)[JWT](./plugins/jwt-auth-cn.md) 等。
377382
2. 获取 consumer_id:通过授权认证,即可自然获取到对应的 Consumer `id`,它是 Consumer 对象的唯一识别标识。
378383
3. 获取 Consumer 上绑定的 Plugin 或 Upstream 信息:完成对不同 Consumer 做不同配置的效果。
379384

380385
概括一下,Consumer 是某类服务的消费者,需与用户认证体系配合才能使用。
381386
比如不同的 Consumer 请求同一个 API,网关服务根据当前请求用户信息,对应不同的 Plugin 或 Upstream 配置。
382387

383-
此外,大家也可以参考 [key-auth](doc/plugins/key-auth.md) 认证授权插件的调用逻辑,辅助大家来进一步理解 Consumer 概念和使用。
388+
此外,大家也可以参考 [key-auth](./plugins/key-auth.md) 认证授权插件的调用逻辑,辅助大家来进一步理解 Consumer 概念和使用。
389+
390+
如何对某个 Consumer 开启指定插件,可以看下面例子:
391+
392+
```shell
393+
# 创建 Consumer ,指定认证插件 key-auth ,并开启特定插件 limit-count
394+
$ curl http://127.0.0.1:9080/apisix/admin/consumers/1 -X PUT -d '
395+
{
396+
"username": "jack",
397+
"plugins": {
398+
"key-auth": {
399+
"key": "auth-one"
400+
},
401+
"limit-count": {
402+
"count": 2,
403+
"time_window": 60,
404+
"rejected_code": 503,
405+
"key": "remote_addr"
406+
}
407+
}
408+
}'
409+
410+
# 创建 Router,设置路由规则和启用插件配置
411+
$ curl http://127.0.0.1:9080/apisix/admin/routes/1 -X PUT -d '
412+
{
413+
"plugins": {
414+
"key-auth": {}
415+
},
416+
"upstream": {
417+
"nodes": {
418+
"127.0.0.1:1980": 1
419+
},
420+
"type": "roundrobin"
421+
},
422+
"uri": "/hello"
423+
}'
424+
425+
# 发测试请求,前两次返回正常,没达到限速阈值
426+
$ curl http://127.0.0.1:9080/hello -H 'apikey: auth-one' -I
427+
...
384428

385-
*注意*:目前 APISIX 的 Consumer 还不支持绑定插件或上游信息,如果大家对这个功能点感兴趣,欢迎在社区中反馈交流。
429+
$ curl http://127.0.0.1:9080/hello -H 'apikey: auth-one' -I
430+
...
431+
432+
# 第三次测试返回 503,请求被限制
433+
$ curl http://127.0.0.1:9080/hello -H 'apikey: auth-one' -I
434+
HTTP/1.1 503 Service Temporarily Unavailable
435+
...
436+
437+
```
386438

387439
[返回目录](#目录)
388440

doc/plugins/jwt-auth-cn.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ curl http://127.0.0.1:9080/apisix/admin/consumers -X PUT -d '
3333
"username": "jack",
3434
"plugins": {
3535
"jwt-auth": {
36-
"key": "your-consumer-key",
37-
"secret": "secret-key"
36+
"key": "user-key",
37+
"secret": "my-secret-key"
3838
}
3939
}
4040
}'
@@ -141,8 +141,7 @@ $ curl http://127.0.0.1:2379/v2/keys/apisix/routes/1 -X PUT -d value='
141141
"methods": ["GET"],
142142
"uri": "/index.html",
143143
"id": 1,
144-
"plugins": {
145-
},
144+
"plugins": {},
146145
"upstream": {
147146
"type": "roundrobin",
148147
"nodes": {

doc/plugins/key-auth-cn.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ curl http://127.0.0.1:9080/apisix/admin/consumers -X PUT -d '
2828
"username": "jack",
2929
"plugins": {
3030
"key-auth": {
31-
"key": "keykey"
31+
"key": "auth-one"
3232
}
3333
}
3434
}'

doc/plugins/key-auth.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,12 @@ Two steps are required:
2525
1. creates a consumer object, and set the attributes of plugin `key-auth`.
2626

2727
```shell
28-
curl http://127.0.0.1:9080/apisix/admin/consumers -X PUT -d '
28+
curl http://127.0.0.1:9080/apisix/admin/consumers -X PUT -d '
2929
{
3030
"username": "jack",
3131
"plugins": {
3232
"key-auth": {
33-
"key": "keykey"
33+
"key": "auth-one"
3434
}
3535
}
3636
}'

lua/apisix.lua

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ function _M.http_access_phase()
250250
core.table.clear(plugins)
251251
api_ctx.plugins = plugin.filter(global_rule, plugins)
252252
run_plugin("rewrite", plugins, api_ctx)
253+
run_plugin("access", plugins, api_ctx)
253254
end
254255

255256
core.tablepool.release("plugins", plugins)
@@ -298,7 +299,7 @@ function _M.http_access_phase()
298299
end
299300

300301
local changed
301-
route, changed = plugin.merge_route(service, route)
302+
route, changed = plugin.merge_service_route(service, route)
302303
api_ctx.matched_route = route
303304

304305
if changed then
@@ -338,6 +339,14 @@ function _M.http_access_phase()
338339
api_ctx.plugins = plugin.filter(route, plugins)
339340

340341
run_plugin("rewrite", plugins, api_ctx)
342+
if api_ctx.consumer then
343+
local changed
344+
route, changed = plugin.merge_consumer_route(route, api_ctx.consumer)
345+
if changed then
346+
core.table.clear(api_ctx.plugins)
347+
api_ctx.plugins = plugin.filter(route, api_ctx.plugins)
348+
end
349+
end
341350
run_plugin("access", plugins, api_ctx)
342351
end
343352

@@ -375,7 +384,7 @@ function _M.grpc_access_phase()
375384
end
376385

377386
local changed
378-
route, changed = plugin.merge_route(service, route)
387+
route, changed = plugin.merge_service_route(service, route)
379388
api_ctx.matched_route = route
380389

381390
if changed then

lua/apisix/admin/consumers.lua

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
local core = require("apisix.core")
1+
local core = require("apisix.core")
22
local plugins = require("apisix.admin.plugins")
3+
local plugin = require("apisix.plugin")
4+
local pairs = pairs
35

46
local _M = {
57
version = 0.1,
@@ -24,13 +26,26 @@ local function check_conf(consumer_name, conf)
2426
return nil, {error_msg = "invalid configuration: " .. err}
2527
end
2628

27-
if not conf.plugins then
28-
return consumer_name
29-
end
30-
31-
ok, err = plugins.check_schema(conf.plugins)
32-
if not ok then
33-
return nil, {error_msg = "invalid configuration: " .. err}
29+
if conf.plugins then
30+
ok, err = plugins.check_schema(conf.plugins)
31+
if not ok then
32+
return nil, {error_msg = "invalid plugins configuration: " .. err}
33+
end
34+
35+
local count_auth_plugin = 0
36+
for name, conf in pairs(conf.plugins) do
37+
local plugin_obj = plugin.get(name)
38+
if plugin_obj.type == 'auth' then
39+
count_auth_plugin = count_auth_plugin + 1
40+
if count_auth_plugin > 1 then
41+
return nil, {error_msg = "only one auth plugin is allowed"}
42+
end
43+
end
44+
end
45+
46+
if count_auth_plugin == 0 then
47+
return nil, {error_msg = "require one auth plugin"}
48+
end
3449
end
3550

3651
return consumer_name

lua/apisix/consumer.lua

Lines changed: 24 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,16 @@
1-
local lrucache = require("apisix.core.lrucache")
2-
local schema = require("apisix.core.schema")
3-
local config = require("apisix.core.config_etcd")
4-
local insert_tab = table.insert
1+
local core = require("apisix.core")
2+
local plugin = require("apisix.plugin")
3+
local error = error
4+
local ipairs = ipairs
5+
local pairs = pairs
56
local consumers
6-
local error = error
7-
local ipairs = ipairs
8-
local pairs = pairs
97

108

119
local _M = {
12-
version = 0.1,
10+
version = 0.2,
1311
}
1412

15-
--[[
16-
{
17-
"id": "ShunFeng",
18-
"plugins": {
19-
"key-auth": {
20-
"key": "dddxxyyy"
21-
}
22-
}
23-
}
2413

25-
to
26-
27-
{
28-
key-auth: [
29-
{
30-
"key": "dddxxyyy",
31-
"consumer_id": "ShunFeng"
32-
}
33-
]
34-
}
35-
]]
3614
local function plugin_consumer()
3715
local plugins = {}
3816

@@ -41,17 +19,23 @@ local function plugin_consumer()
4119
end
4220

4321
for _, consumer in ipairs(consumers.values) do
44-
for name, conf in pairs(consumer.value.plugins) do
45-
if not plugins[name] then
22+
for name, config in pairs(consumer.value.plugins or {}) do
23+
local plugin_obj = plugin.get(name)
24+
if plugin_obj and plugin_obj.type == "auth"
25+
and not plugins[name] then
4626
plugins[name] = {
4727
nodes = {},
48-
conf_version = consumers.conf_version,
28+
conf_version = consumers.conf_version
4929
}
50-
end
5130

31+
local new_consumer = core.table.clone(consumer.value)
32+
new_consumer.consumer_id = new_consumer.id
33+
new_consumer.auth_conf = config
34+
core.log.info("consumer:", core.json.delay_encode(new_consumer))
35+
core.table.insert(plugins[name].nodes, new_consumer)
5236

53-
insert_tab(plugins[name].nodes,
54-
{consumer_id = consumer.value.id, conf = conf})
37+
break
38+
end
5539
end
5640
end
5741

@@ -60,19 +44,18 @@ end
6044

6145

6246
function _M.plugin(plugin_name)
63-
local plugin_conf = lrucache.global("/consumers",
64-
consumers.conf_version, plugin_consumer)
47+
local plugin_conf = core.lrucache.global("/consumers",
48+
consumers.conf_version, plugin_consumer)
6549
return plugin_conf[plugin_name]
6650
end
6751

6852

6953
function _M.init_worker()
7054
local err
71-
consumers, err = config.new("/consumers",
72-
{
73-
automatic = true,
74-
item_schema = schema.consumer
75-
})
55+
consumers, err = core.config.new("/consumers", {
56+
automatic = true,
57+
item_schema = core.schema.consumer
58+
})
7659
if not consumers then
7760
error("failed to create etcd instance for fetching consumers: " .. err)
7861
return

lua/apisix/core.lua

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,5 @@ return {
2121
utils = require("apisix.core.utils"),
2222
etcd = require("apisix.core.etcd"),
2323
http = require("apisix.core.http"),
24-
consumer = require("apisix.consumer"),
2524
tablepool= require("tablepool"),
2625
}

0 commit comments

Comments
 (0)