feat: add rejected_message support for plugin request-validation (#5122)

This commit is contained in:
leslie 2021-09-28 10:17:08 +08:00 committed by GitHub
parent c3635d46ef
commit 76540a57f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 339 additions and 75 deletions

View File

@ -17,27 +17,20 @@
local core = require("apisix.core")
local plugin_name = "request-validation"
local ngx = ngx
local io = io
local io = io
local req_read_body = ngx.req.read_body
local req_get_body_data = ngx.req.get_body_data
local schema = {
type = "object",
properties = {
header_schema = {type = "object"},
body_schema = {type = "object"},
rejected_msg = {type = "string", minLength = 1, maxLength = 256}
},
anyOf = {
{
title = "Body schema",
properties = {
body_schema = {type = "object"}
},
required = {"body_schema"}
},
{
title = "Header schema",
properties = {
header_schema = {type = "object"}
},
required = {"header_schema"}
}
{required = {"header_schema"}},
{required = {"body_schema"}}
}
}
@ -82,7 +75,7 @@ function _M.rewrite(conf)
local ok, err = core.schema.check(conf.header_schema, headers)
if not ok then
core.log.error("req schema validation failed", err)
return 400, err
return 400, conf.rejected_msg or err
end
end
@ -94,11 +87,11 @@ function _M.rewrite(conf)
if not body then
local filename = ngx.req.get_body_file()
if not filename then
return 500
return 500, conf.rejected_msg
end
local fd = io.open(filename, 'rb')
if not fd then
return 500
return 500, conf.rejected_msg
end
body = fd:read('*a')
end
@ -111,13 +104,13 @@ function _M.rewrite(conf)
if not req_body then
core.log.error('failed to decode the req body', error)
return 400, error
return 400, conf.rejected_msg or error
end
local ok, err = core.schema.check(conf.body_schema, req_body)
if not ok then
core.log.error("req schema validation failed", err)
return 400, err
return 400, conf.rejected_msg or err
end
end
end

View File

@ -39,10 +39,13 @@ For more information on schema, refer to [JSON schema](https://github.com/api7/j
## Attributes
| Name | Type | Requirement | Default | Valid | Description |
| ------------- | ------ | ----------- | ------- | ----- | -------------------------- |
| header_schema | object | optional | | | schema for the header data |
| body_schema | object | optional | | | schema for the body data |
> Note that at least one of `header_schema` and `body_schema` must be filled in.
| Name | Type | Requirement | Default | Valid | Description |
| ---------------- | ------ | ----------- | ------- | ----- | -------------------------- |
| header_schema | object | optional | | | schema for the header data |
| body_schema | object | optional | | | schema for the body data |
| rejected_message | string | optional | | | the custom rejected message |
## How To Enable
@ -60,7 +63,8 @@ curl http://127.0.0.1:9080/apisix/admin/routes/5 -H 'X-API-KEY: edd1c9f034335f13
"properties": {
"required_payload": {"type": "string"},
"boolean_payload": {"type": "boolean"}
}
},
"rejected_message": "customize reject message"
}
}
},
@ -82,7 +86,7 @@ curl --header "Content-Type: application/json" \
http://127.0.0.1:9080/get
```
If the schema is violated the plugin will yield a `400` bad request.
If the schema is violated the plugin will yield a `400` bad request with the reject response.
## Disable Plugin
@ -252,3 +256,30 @@ curl http://127.0.0.1:9080/apisix/admin/routes/5 -H 'X-API-KEY: edd1c9f034335f13
}
}
```
**Custom rejected message:**
```json
{
"uri": "/get",
"plugins": {
"request-validation": {
"body_schema": {
"type": "object",
"required": ["required_payload"],
"properties": {
"required_payload": {"type": "string"},
"boolean_payload": {"type": "boolean"}
},
"rejected_message": "customize reject message"
}
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:8080": 1
}
}
}
```

View File

@ -38,10 +38,13 @@ title: request-validation
## 属性
| Name | Type | Requirement | Default | Valid | Description |
| ------------- | ------ | ----------- | ------- | ----- | --------------------------------- |
| header_schema | object | 可选 | | | `header` 数据的 `schema` 数据结构 |
| body_schema | object | 可选 | | | `body` 数据的 `schema` 数据结构 |
> 注意, `header_schema``body_schema` 至少填写其中一个
| Name | Type | Requirement | Default | Valid | Description |
| ---------------- | ------ | ----------- | ------- | ----- | --------------------------------- |
| header_schema | object | 可选 | | | `header` 数据的 `schema` 数据结构 |
| body_schema | object | 可选 | | | `body` 数据的 `schema` 数据结构 |
| rejected_message | string | 可选 | | | 自定义拒绝信息 |
## 如何启用
@ -59,7 +62,8 @@ curl http://127.0.0.1:9080/apisix/admin/routes/5 -H 'X-API-KEY: edd1c9f034335f13
"properties": {
"required_payload": {"type": "string"},
"boolean_payload": {"type": "boolean"}
}
},
"rejected_message": "customize reject message"
}
}
},
@ -81,7 +85,7 @@ curl --header "Content-Type: application/json" \
http://127.0.0.1:9080/get
```
如果 `Schema` 验证失败,将返回 `400 bad request` 错误
如果 `Schema` 验证失败,将返回 `400` 状态码与相应的拒绝信息
## 禁用插件
@ -250,3 +254,30 @@ curl http://127.0.0.1:9080/apisix/admin/routes/5 -H 'X-API-KEY: edd1c9f034335f13
}
}
```
**自定义拒绝信息:**
```json
{
"uri": "/get",
"plugins": {
"request-validation": {
"body_schema": {
"type": "object",
"required": ["required_payload"],
"properties": {
"required_payload": {"type": "string"},
"boolean_payload": {"type": "boolean"}
},
"rejected_message": "customize reject message"
}
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:8080": 1
}
}
}
```

View File

@ -61,9 +61,8 @@ done
}
--- request
GET /t
--- response_body
object matches none of the requireds: ["body_schema"] or ["header_schema"]
done
--- response_body_like eval
qr/object matches none of the requireds/
--- no_error_log
[error]
@ -375,8 +374,6 @@ hello1 world
GET /t
--- response_body
passed
--- error_code chomp
200
--- no_error_log
[error]
@ -415,8 +412,6 @@ passed
GET /t
--- response_body
passed
--- error_code chomp
200
--- no_error_log
[error]
@ -455,8 +450,6 @@ passed
GET /t
--- response_body
passed
--- error_code chomp
200
--- no_error_log
[error]
@ -495,8 +488,6 @@ passed
GET /t
--- response_body
passed
--- error_code chomp
200
--- no_error_log
[error]
@ -535,8 +526,6 @@ passed
GET /t
--- response_body
passed
--- error_code chomp
200
--- no_error_log
[error]
@ -575,8 +564,6 @@ passed
GET /t
--- response_body
passed
--- error_code chomp
200
--- no_error_log
[error]
@ -615,8 +602,6 @@ passed
GET /t
--- response_body
passed
--- error_code chomp
200
--- no_error_log
[error]
@ -655,8 +640,6 @@ passed
GET /t
--- response_body
passed
--- error_code chomp
200
--- no_error_log
[error]
@ -787,8 +770,6 @@ qr/table expected, got string/
GET /t
--- response_body
passed
--- error_code chomp
200
--- no_error_log
[error]
@ -881,8 +862,6 @@ qr/table expected, got string/
GET /t
--- response_body
passed
--- error_code chomp
200
--- no_error_log
[error]
@ -939,8 +918,6 @@ passed
GET /t
--- response_body
passed
--- error_code chomp
200
--- no_error_log
[error]
@ -979,8 +956,6 @@ passed
GET /t
--- response_body
passed
--- error_code chomp
200
--- no_error_log
[error]
@ -1019,8 +994,6 @@ passed
GET /t
--- response_body
passed
--- error_code chomp
200
--- no_error_log
[error]
@ -1059,8 +1032,6 @@ passed
GET /t
--- response_body
passed
--- error_code chomp
200
--- no_error_log
[error]
@ -1099,8 +1070,6 @@ passed
GET /t
--- response_body
passed
--- error_code chomp
200
--- no_error_log
[error]
@ -1139,8 +1108,6 @@ passed
GET /t
--- response_body
passed
--- error_code chomp
200
--- no_error_log
[error]
@ -1179,8 +1146,6 @@ passed
GET /t
--- response_body
passed
--- error_code chomp
200
--- no_error_log
[error]
@ -1219,8 +1184,6 @@ passed
GET /t
--- response_body
passed
--- error_code chomp
200
--- no_error_log
[error]
@ -1351,8 +1314,6 @@ qr/table expected, got string/
GET /t
--- response_body
passed
--- error_code chomp
200
--- no_error_log
[error]
@ -1445,7 +1406,255 @@ qr/table expected, got string/
GET /t
--- response_body
passed
--- error_code chomp
200
--- no_error_log
[error]
=== TEST 35: add route (test request validation `header_schema.required` success with custom reject message)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"request-validation": {
"header_schema": {
"type": "object",
"properties": {
"test": {
"type": "string",
"enum": ["a", "b", "c"]
}
},
"required": ["test"]
},
"rejected_msg": "customize reject message for header_schema.required"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1982": 1
},
"type": "roundrobin"
},
"uri": "/opentracing"
}]])
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
--- no_error_log
[error]
=== TEST 36: use empty header to hit `header_schema.required with custom reject message` rule
--- request
GET /opentracing
--- error_code: 400
--- response_body chomp
customize reject message for header_schema.required
--- error_log eval
qr/schema validation failed/
=== TEST 37: use bad header value to hit `header_schema.required with custom reject message` rule
--- request
GET /opentracing
--- more_headers
test: abc
--- error_code: 400
--- response_body chomp
customize reject message for header_schema.required
--- error_log eval
qr/schema validation failed/
=== TEST 38: pass `header_schema.required with custom reject message` rule
--- request
GET /opentracing
--- more_headers
test: a
--- error_code: 200
--- response_body eval
qr/opentracing/
--- no_error_log
[error]
=== TEST 39: add route (test request validation `body_schema.required` success with custom reject message)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"request-validation": {
"body_schema": {
"type": "object",
"properties": {
"test": {
"type": "string",
"enum": ["a", "b", "c"]
}
},
"required": ["test"]
},
"rejected_msg": "customize reject message for body_schema.required"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1982": 1
},
"type": "roundrobin"
},
"uri": "/opentracing"
}]])
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
--- no_error_log
[error]
=== TEST 40: use empty body to hit `body_schema.required with custom reject message` rule
--- request
GET /opentracing
--- error_code: 500
--- response_body chomp
customize reject message for body_schema.required
--- no_error_log
[error]
=== TEST 41: use bad body value to hit `body_schema.required with custom reject message` rule
--- request
POST /opentracing
{"test":"abc"}
--- error_code: 400
--- response_body chomp
customize reject message for body_schema.required
--- error_log eval
qr/schema validation failed/
=== TEST 42: pass `body_schema.required with custom reject message` rule
--- request
POST /opentracing
{"test":"a"}
--- error_code: 200
--- response_body eval
qr/opentracing/
--- no_error_log
[error]
=== TEST 43: add route (test request validation `header_schema.required` failure with custom reject message)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"request-validation": {
"header_schema": {
"type": "object",
"properties": {
"test": {
"type": "string",
"enum": ["a", "b", "c"]
}
},
"required": ["test"]
},
"rejected_msg": "customize reject message customize reject message customize reject message customize reject message customize reject message customize reject message customize reject message customize reject message customize reject message customize reject message customize reject message"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1982": 1
},
"type": "roundrobin"
},
"uri": "/plugin/request/validation"
}]])
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body_like eval
qr/string too long/
--- error_code chomp
400
--- no_error_log
[error]
=== TEST 44: add route (test request validation schema with custom reject message only)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"request-validation": {
"rejected_message": "customize reject message"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1982": 1
},
"type": "roundrobin"
},
"uri": "/plugin/request/validation"
}]])
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body_like eval
qr/object matches none of the requireds/
--- error_code chomp
400
--- no_error_log
[error]