«

»

Dec 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这里也有很多问题,在这里就不一一描述了。坑都不是很大,多数情况下都可以满足需求。

14 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 就出现 错误 什么什么原因? 楼主能帮忙解答嘛?

  6. SparkleBO

    Scope是什么意思啊

    1. 石樱灯笼

      token的权限范围

  7. xiaoxiao

    后端有多个实例提供服务应该如何配置

    1. 石樱灯笼

      当时研究 Kong 的时候,公司买的负载均衡,且实现非常不优雅,没有一丝参考价值,所以最终并没有写进文内。
      至于 Kong 自己的负载均衡以及 后端API 的负载均衡,当时没有时间去学习。而由于公司项目组也没有活到项目开发完成,所以也没有再深入研究。
      Kong v0.10 之后的版本与 v0.9 版本差异也很大,现在版本已经到 0.11.2 了,而且还分了社区版和企业版。想要使用的话建议重新学习新版本。

发表评论

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

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据