«

»

十二 20 2016

基于Kong建立支持OAuth2.0的API网关

有些时候你会为一个产品制作很多功能,而这些功能往往需要相同的用户认证系统,相同的接口统计系统。为每个功能都复制模块代码实在不是什么好主意。

这个时候,你需要一个API网关,统一管理各个接口的各种功能,比如SSL证书,OAuth2验证等。

本文编写时 Kong 版本为 0.9.5,本文适用于 0.9.5-0.9.9 之间的版本。目前 Kong 已升级到 0.10,API变化很大,本文的部分内容将不再适用,请读者注意!

概念

  • Kong

Kong 是一个开源的 API网关,你也可以认为他是一个 API中间件。对于一个API中间件,Kong将此思维发挥到了极致,所有对Kong配置的增加和修改,也都是依靠 RESTful API 来操作。

Kong 非常适合于管理后端基于 Docker 等以微服务形式实现的 API 接口。官网:https://getkong.org/

本文将基于 Kong 0.9.5 版本进行实现。

  • OAuth2

OAuth2 我就不讲是什么了

实现Kong完成API转发

需求和现状

我们将要为以下服务实现API请求转发:

  • Web服务X,地址为10.0.0.100:8081
  • Web服务Y,地址为10.0.0.100:8082
  • Web服务Z,地址为10.0.0.100:8083,此服务器提供用户信息服务,可用于保存或验证用户的账号密码。

Kong服务器地址:10.0.1.0,域名:www.your-kong-domain.com

安装和启动

本文的安装全部使用Docker进行安装。对于Docker的使用方式,请参见我之前的文章

  • 安装并启动cassandra数据库

注意这个服务启动的速度非常慢,我在阿里云上启动这个服务,9042端口生效需要18秒(cassandra官网给出的wait-for-it.sh只等了15秒就受不了了),启动真的很慢,太着急而启动 Kong服务 的话会出现数据库连接失败而推出的问题。

  • 安装并启动Kong

这个服务启动也很慢,急着进行下一步启动 kong-dashboard 连接端口也会报错,不能着急。kong 的 docker 版本做的还不够好,日志并没有连到标准输入输出上,需要的话可以进入容器内查看。日志地址:/usr/local/kong/logs/

  • 安装并启动 kong-dashboard

由于 Kong 对 RESTful API 的极致使用简直到了强迫症的程度,所以对于某些操作,有一个高效的 UI 界面要比在纯命令行模式下更容易观察和操作。

kong-dashboard是一个开源的Kong UI管理工具。其UI使用的框架是我非常喜欢的 Materialize。项目地址:https://github.com/PGBI/kong-dashboard

打开Kong服务器的8080端口,就可以进入 kong-dashboard 的界面了。

填写我们的Kong管理地址和端口8001,就可以进入管理页面了。

策略模式

官方文档:https://getkong.org/docs/0.5.x/admin-api/

为了便于理解,将Kong目前能实现模式简单分为两种,以便于理解:Request host 和 Request path。

Request host:

要在Kong服务器上绑定多个域名。(提供api服务的服务器可以没有域名绑定,只要有IP即可)

Request path

Kong服务器上只需要绑定一个域名,不同的API集合依靠不同的请求路径实现。(同上,提供api服务的服务器可以没有域名绑定,只要有IP即可)

Request host 和 Request path 可组合使用,但比较复杂,不建议使用。

新建API策略

我们新建一条名为service1的策略,将请求转发到 http://110.0.0.100:8081

两个参数:

  • strip_request_path:在使用 Request path 模式会用到的参数。

如果开启时效果是这样的:

不开启时则是:

根据你后端进行设计和配置。

我们这次使用的是Request host,用不到这个参数。(默认不开启)

  • preserve_host:不开启此项的话,API服务器收到的请求中,HOST参数和SERVER_NAME为API服务器。开启则为Kong服务器绑定的域名。(默认不开启)

点击保存后,访问 kong.yourname.com,就能打开 http://110.0.0.100:8081 了。

开启HTTPS

使用 OAuth2 的前提便是你的接口是HTTPS的,所以我们先开启HTTPS。

貌似 kong-dashboard 的 ssl 插件也可以实现,不过为了理解下Kong的RESTFUL API,所以添加SSL证书的步骤,我们全部都采用使用命令行添加的方式。

Let’s encrypt 人工申请证书

(如果暂时没有域名,或者不打算麻烦 Let’s encrypt 或其他认证机构,也可以跳过,kong的https端口上默认绑着localhost的自签证书用于开发环境和测试。可以跳过此段)

虽然 Let’s encrypt 提供了非常多的方法让大家申请可信任的 ssl证书,然而我还是更喜欢人工申请证书文件,手动导入到服务器。这么做比较有真实感,另外因为服务器总要换来换去,总麻烦人家 Let’s encrypt 也不好,还是证书文件最实在。

这里就不解释申请的方法了。

 

最终你会得到四个文件:

证书文件、链文件、全链文件、私钥文件。证书和私钥就不解释了,全链文件就是证书和私钥加一起,适用于比较新的http服务器。链文件是啥至今没搞懂,也不知道在哪用。

使用SSL插件导入证书

注意:SSL插件只适用于 request_host 模式!!!

访问你API的HTTPS地址:https://api.your-kong-domain.com/node1/,检查证书绑定情况。

对于 request_path 模式,不需要使用插件,只需要修改 Kong 的配置文件即可。这个部分没有提供 API,需要手动修改kong.conf。相关文档:https://getkong.org/docs/0.9.x/configuration/#ssl_cert_path

实现OAuth2 验证

我们来实现一个 WebApp 常用的 密码模式(Resource Owner Password Credentials Grant)OAuth2 接口验证。

这个实例与官方实例略有不同。官方的用户认证服务器在Kong的外侧,用户直接访问。而我们的例子中,用户认证服务器在Kong的内侧,我们需要通过Kong进行访问。其他条件没有区别,整体核心思路是相同的。

整体流程图

解释:

  1. 用户发送账号密码到 Kong服务器的用户验证API;
  2. Kong服务器将请求1转发给用户验证服务器;
  3. 用户认证服务器验证用户账号密码是否正确,如果不正确直接返回错误结果并完成用户认证;如果正确则将:用户账号密码client_idclient_secretscopeprovision_key用户ID 发送给 Kong 的OAuth2 接口
  4. Kong生成access_token并返回给用户认证服务器,并缓存与过期时间相同的 scope用户ID
  5. 认证服务器将4中收到的access_token返回请求2给Kong,Kong再返回请求1给用户。
  6. 用户得到access_token之后,就可以访问有OAuth2验证的接口了。access_token中已隐含了用户ID和scope。

实现

增加consumer

添加一个consumer,设置Username:oauth_test,Custom id:100。点击保存。

回到comsumers列表,点击编辑刚才添加的oauth_test。在最下方点击OAUTH2,新建oauth2 credentials。

  • Username:oauth_test_credential
  • Client_id:留空,自动生成
  • Client_secret:留空,自动生成
  • Redirect URI:密码模式在这里用不到,但是此字段不能为空,于是你随便填一个吧

点击创建。Kong会自动生成 Client ID 和 Client Secret。这两个信息将用于我们的 WebApp。

为接口增加OAuth2验证

我们为 策略 node1:https://www.your-kong-domain.com/node1 → http://10.0.0.100:8081/node1 添加 OAuth2 验证。

  • mandatory_scope: 强制需要scope,至少需要一个scope来验证用户权限
  • implicit_grant: 简化模式
  • hide_credentials: 隐藏凭据,开启后,后端API就看不到access_token
  • password_grant: 密码模式
  • accept_http_if_already_terminated: 接受HTTP请求
  • client_credentials: 客户端模式
  • authorization_code: 授权码模式

我们需要勾选 hide_credentials 和 password_grant

准备用户认证服务器

新建一个API策略auth:https://www.your-kong-domain.com/auth/ → http://10.0.0.100:8083/auth/

并且在认证服务器上新建脚本test.php:

当用户名为abc且密码为123的时候就算账号密码正确,否则认证失败。

注意 $url 那里已经写死了 node1,对于实际使用时,应该在用户请求中将对应的api当做参数与用户名和密码同时传进来。

测试请求

最终会从msg中得到:

现在向需要OAuth2认证的接口写一个新的php文件:

发起OAuth2请求:

响应:

可以在Header中看到,scope和userid已经传过来了。

整个基于Kong的OAuth2认证就完成了。

总结

目前 Kong 的版本已经升级到了 0.9.6,但仍有很多功能缺失。Kong 是基于 NGINX 开发实现的,然而很多 NGINX 已经实现的功能,比如 Websocket 转发,仍没有完全支持。下一个版本或许会开始支持 Websocket。OAuth2这里也有很多问题,在这里就不一一描述了。坑都不是很大,多数情况下都可以满足需求。

10 comments

Skip to comment form

  1. 慕若曦

    圣诞节快乐

    1. 石樱灯笼

      域名留错了,pw怎么变com了

      1. 慕若曦

        被浏览器的填充给坑了……

        1. 石樱灯笼

          都被坑过

  2. 小彦

    开懂一点点,大概是一个Auth服务相关的?
    还有子域名路由和alias功能?

  3. 夏天烤洋芋

    不知道这是干嘛的!

    1. 石樱灯笼

      微服务架构的网站会用的东西

  4. xiaopanp

    有用过Kong+consul?

    1. 石樱灯笼

      没有

  5. viable

    您好
    请问 我ip:8080 填写 IP:8001 就出现 错误 什么什么原因? 楼主能帮忙解答嘛?

发表评论

电子邮件地址不会被公开。 必填项已用*标注