Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: supported JWT plugin and added test cases. #303

Merged
merged 2 commits into from
Jul 24, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions COPYRIGHT
Original file line number Diff line number Diff line change
Expand Up @@ -206,3 +206,36 @@ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

%%%%%%%%%

lua-resty-jwt

https://github.com/cdbattags/lua-resty-jwt
https://github.com/cdbattags/lua-resty-jwt/blob/master/LICENSE

https://github.com/SkyLothar/lua-resty-jwt
https://github.com/SkyLothar/lua-resty-jwt/blob/master/LICENSE

Apache License 2

%%%%%%%%%

lua-resty-cookie

https://github.com/cloudflare/lua-resty-cookie

This module is licensed under the BSD license.

Copyright (C) 2013, by Jiale Zhi vipcalio@gmail.com, CloudFlare Inc.

Copyright (C) 2013, by Yichun Zhang agentzh@gmail.com, CloudFlare Inc.

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

1 change: 1 addition & 0 deletions conf/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ plugins: # plugin list
- prometheus
- limit-conn
- node-status
- jwt-auth
153 changes: 153 additions & 0 deletions doc/plugins/jwt-auth-cn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
[English](jwt-auth.md)

# 目录
- [**名字**](#名字)
- [**属性**](#属性)
- [**如何启用**](#如何启用)
- [**测试插件**](#测试插件)
- [**禁用插件**](#禁用插件)


## 名字

`jwt-auth` 是一个认证插件,它需要与 `consumer` 一起配合才能工作。

添加 JWT Authentication 到一个 `service` 或 `route`。 然后,`consumer` 将其密钥添加到查询字符串参数、请求头或 `cookie` 中以验证其请求。

有关 JWT 的更多信息,可移步 [JWT](https://jwt.io/) 查看更多信息。

## 属性

* `key`: 不同的 `consumer` 对象应有不同的值,它应当是唯一的。不同 consumer 使用了相同的 `key` ,将会出现请求匹配异常。
* `secret`: 可选字段,加密秘钥。如果您未指定,后台将会自动帮您生成。
* `algorithm`:可选字段,加密算法。目前支持 `HS256`, `HS384`, `HS512`, `RS256` 和 `ES256`,如果未指定,则默认使用 `HS256`。
* `exp`: 可选字段,token 的超时时间,以秒为单位的计时。比如有效期是 5 分钟,那么就应设置为 `5 * 60 = 300`。

## 如何启用

1. 创建一个 consumer 对象,并设置插件 `jwt-auth` 的值。

```shell
curl http://127.0.0.1:9080/apisix/admin/consumers -X PUT -d '
{
"username": "jack",
"plugins": {
"jwt-auth": {
"key": "user-key",
"secret": "secret-key"
}
}
}'
```

2. 创建 route 或 service 对象,并开启 `jwt-auth` 插件。

```shell
curl http://127.0.0.1:9080/apisix/admin/routes/1 -X PUT -d '
{
"methods": ["GET"],
"uri": "/index.html",
"plugins": {
"jwt-auth": {}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"39.97.63.215:80": 1
}
}
}'
```

## Test Plugin

#### 首先进行登录获取 `jwt-auth` token:

```shell
$ curl http://127.0.0.2:9080/apisix/plugin/jwt/sign?key=user-key -i
HTTP/1.1 200 OK
Date: Wed, 24 Jul 2019 10:33:31 GMT
Content-Type: text/plain
Transfer-Encoding: chunked
Connection: keep-alive
Server: APISIX web server

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTU2NDA1MDgxMX0.Us8zh_4VjJXF-TmR5f8cif8mBU7SuefPlpxhH0jbPVI
```

#### 使用获取到的 token 进行请求尝试

* 缺少 token

```shell
$ curl http://127.0.0.2:9080/index.html -i
HTTP/1.1 401 Unauthorized
...
{"message":"Missing JWT token in request"}
```

* token 放到请求头中:

```shell
$ curl http://127.0.0.2:9080/index.html -H 'Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTU2NDA1MDgxMX0.Us8zh_4VjJXF-TmR5f8cif8mBU7SuefPlpxhH0jbPVI' -i
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 13175
...
Accept-Ranges: bytes

<!DOCTYPE html>
<html lang="cn">
...
```

* token 放到请求参数中:

```shell
$ curl http://127.0.0.2:9080/index.html?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTU2NDA1MDgxMX0.Us8zh_4VjJXF-TmR5f8cif8mBU7SuefPlpxhH0jbPVI -i
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 13175
...
Accept-Ranges: bytes

<!DOCTYPE html>
<html lang="cn">
...
```

* token 放到 cookie 中:

```shell
$ curl http://127.0.0.2:9080/index.html --cookie jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTU2NDA1MDgxMX0.Us8zh_4VjJXF-TmR5f8cif8mBU7SuefPlpxhH0jbPVI -i
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 13175
...
Accept-Ranges: bytes

<!DOCTYPE html>
<html lang="cn">
...
```

## 禁用插件

当你想去掉 `jwt-auth` 插件的时候,很简单,在插件的配置中把对应的 `json` 配置删除即可,无须重启服务,即刻生效:

```shell
$ curl http://127.0.0.1:2379/v2/keys/apisix/routes/1 -X PUT -d value='
{
"methods": ["GET"],
"uri": "/index.html",
"id": 1,
"plugins": {
},
"upstream": {
"type": "roundrobin",
"nodes": {
"39.97.63.215:80": 1
}
}
}'
```
10 changes: 10 additions & 0 deletions lua/apisix/admin/consumers.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
local core = require("apisix.core")
local plugins = require("apisix.admin.plugins")

local _M = {
version = 0.1,
Expand All @@ -23,6 +24,15 @@ local function check_conf(consumer_name, conf)
return nil, {error_msg = "invalid configuration: " .. err}
end

if not conf.plugins then
return consumer_name
end

ok, err = plugins.check_schema(conf.plugins)
if not ok then
return nil, {error_msg = "invalid configuration: " .. err}
end

return consumer_name
end

Expand Down
2 changes: 1 addition & 1 deletion lua/apisix/admin/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ local function run(params)
local data, err = core.json.decode(req_body)
if not data then
core.log.error("invalid request body: ", req_body, " err: ", err)
core.response.exit(401, {error_msg = "invalid request body",
core.response.exit(400, {error_msg = "invalid request body",
req_body = req_body})
end

Expand Down
3 changes: 3 additions & 0 deletions lua/apisix/core/id.lua
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ local function write_file(path, data)
end


_M.gen_uuid_v4 = uuid.generate_v4


function _M.init()
local uid_file_path = prefix .. "/conf/apisix.uid"
apisix_uid = read_file(uid_file_path)
Expand Down
Loading