You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

134 lines
8.5 KiB
Markdown

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 44 | 实战(四):“画图”程序后端实战
你好,我是七牛云许式伟。
上一讲我们介绍了帐号与授权相关的基础体系,并重点介绍 OAuth 2.0 背后的逻辑。今天我们开始考虑如何让 QPaint 引入帐号与授权体系。
最常规的做法,当然是自己建立一个帐号数据库,做基于用户名+密码的登录授权并转为基于Cookie的会话Session。示例如下
* [https://github.com/qiniu/qpaint/tree/v44-bear](https://github.com/qiniu/qpaint/tree/v44-bear)
* [https://github.com/qiniu/qpaint/compare/v42...v44-bear](https://github.com/qiniu/qpaint/compare/v42...v44-bear)
但我们考虑提供 Open API 的话,就需要考虑遵循 OAuth 2.0 的授权协议规范,以便第三方应用可以快速接入,而不是搞半天去研究我们自己发明的授权是怎么回事。
除此之外,我们也可以考虑基于微信、支付宝等 OpenID 来实现用户的快速登录,而不是让用户在注册环节折腾半天。
所以,比较理想的方式是我们基于 [OpenID Connect](https://openid.net/connect/) 协议来提供帐号系统,基于 OAuth 2.0 协议来实现 [Open API](https://oauth.net/2/) 体系。
这个选择与业务无关。所以很自然地,我们决定评估一下,看看是否有开源项目和我们想得一样。
最后,我们发现 CoreOS 团队搞了一个叫 dex 的项目,如下:
* [https://github.com/dexidp/dex](https://github.com/dexidp/dex)
* [https://github.com/xushiwei/dex](https://github.com/xushiwei/dex) (部分依赖库受 GFW 的影响,我们调整 Makefile 改为基于 go -mod=vendor 来编译。)
dex 项目的这么描述自己的:
> dex - A federated OpenID Connect provider
> OpenID Connect Identity (OIDC) and OAuth 2.0 Provider with Pluggable Connectors.
> Dex is an identity service that uses OpenID Connect to drive authentication for other apps. Dex acts as a portal to other identity providers through "connectors." This lets dex defer authentication to LDAP servers, SAML providers, or established identity providers like GitHub, Google, and Active Directory. Clients write their authentication logic once to talk to dex, then dex handles the protocols for a given backend.
概要来说dex 基于各类主流的 OpenID 来提供帐号系统,上游的 OpenID Provider即下图中的 Upstream IdP是以插件方式Pluggable Connector提供。这也是为什么把它叫联邦 OpenIDfederated OpenID的原因。然后dex 再通过 OAuth 2.0 协议对客户端(即下图中的 Client app提供授权服务。
![图片: https://uploader.shimo.im/f/8SVN4368jw0ZFDNG.png](https://static001.geekbang.org/resource/image/08/7c/08f27c67c945d18b16bdcb6e61c22a7c.png?wh=760*460)
## 联邦 OpenID
我们先看 dex 在联邦 OpenID 这块的支持。当前已经支持的 Pluggable Connector 如下:
![](https://static001.geekbang.org/resource/image/80/d1/80204fe57a0fb569a258e98a3fe4d3d1.png?wh=891*474)
可以看出,对于那些支持 [OpenID Connect](https://openid.net/connect/) 协议的 OpenID比如 Google、Saleforce、Azure 等,可以统一用同一个 Connector 来支持。而对于其他的 OpenID比如 Github则实现一个独立的 Connector 来支持。
除了 OpenID Connect我们也可以看到很多耳熟能详的开放帐号授权协议比如在前面课程中有人提议讲一讲的单点登录 SAML 2.0 和 LDAP。但这的确不是我们的重点。我们这里提供相关的链接供大家参考。
LDAP 的资料如下:
* [https://www.openldap.org/](https://www.openldap.org/)
SAML 2.0 Web Browser Single-Sign-On 的资料如下:
* [https://en.wikipedia.org/wiki/SAML\_2.0](https://en.wikipedia.org/wiki/SAML_2.0)
* [http://docs.oasis-open.org/security/saml/Post2.0/sstc-saml-tech-overview-2.0.html](http://docs.oasis-open.org/security/saml/Post2.0/sstc-saml-tech-overview-2.0.html)
不同的 OpenID Provider 作为后端,会导致一些细节上的差异。有的 OpenID Provider 不支持更新令牌Refresh Token有的会导致 ID Token 不支持 groups 字段。详细在以上 Connector 列表中有明确说明。
另外,虽然 dex 支持了颇为丰富的 OpenID Provider但不幸的是国内的主流 OpenID Provider比如微信和支付宝都没有在支持之列。
不过好在它基于开放的插件机制我们可以自己依葫芦画瓢实现一个。Pluggable Connector 相关的文档和插件如下:
* [https://godoc.org/github.com/dexidp/dex/connector](https://godoc.org/github.com/dexidp/dex/connector)
国内也会有人想到做类似 dex 这种项目,比如:
* [https://github.com/tiantour/union](https://github.com/tiantour/union)
看到我们熟悉的微信、支付宝、新浪微博了,所以想到点子并不难,但看架构设计就会看到两者巨大的差距。
当然,如果你看到了其他很好的开源实现,欢迎留言交流。
## 提供 OpenID + OAuth 2.0 服务
尽管 dex 底层所基于的 OpenID Provider 多种多样,但是 dex 对外统一提供了标准的 [OpenID Connect](https://openid.net/connect/) 协议和 [OAuth 2.0](https://oauth.net/2/) 服务。
OpenID Connect 作为 OAuth 2.0 的一个扩展最重要的一个改进是引入了身份令牌ID Token概念。
为什么需要扩展 OAuth 2.0
因为 OAuth 2.0 本身只关心授权所以它会返回访问令牌Access Token和更新令牌Refresh Token。但无论是访问令牌还是更新令牌都并没有包含身份Identity信息。没有身份信息就没法作为 OpenID Provider。
身份令牌ID Token解决了这一问题。ID Token 是一个 [JSON Web Token (JWT)](https://jwt.io) ,支持你对 Token 进行解码decode并验证verify用户身份。关于 JSON Web Token 的详细介绍,请参阅 [https://jwt.io/](https://jwt.io/) 。
dex 并不是一个包package而是一个可执行程序application它提供了帐号与授权服务。你可以这样运行它
```
dex config.yaml
```
其中 config.yaml 是它的配置文件。其格式可参考以下这些样例:
* [examples/config-dev.yaml](https://github.com/xushiwei/dex/blob/master/examples/config-dev.yaml)(开发用途,用 mock 的帐号与授权服务。)
* [examples/config-ldap.yaml](https://github.com/xushiwei/dex/blob/master/examples/config-ldap.yaml)(基于 LDAP 来做帐号与授权服务。)
## 使用 dex
有了 dex 服务,我们就可以开始回到 QPaint 业务,去支持帐号与授权了。
我们并不需要自己开发太多东西。
OAuth 2.0 的客户端 SDKGo 语言自己有一个准官方的版本。如下:
* 包名:[golang.org/x/oauth2](https://godoc.org/golang.org/x/oauth2)
* 项目地址:[https://github.com/golang/oauth2/](https://github.com/golang/oauth2/)
OpenID Connect 的客户端 SDKCoreOS 团队也开发了一个。如下:
* [https://github.com/coreos/go-oidc](https://github.com/coreos/go-oidc)
具体如何对接 dexCoreOS 团队也写了一个详细的说明文档。如下:
* [https://github.com/xushiwei/dex/blob/master/Documentation/using-dex.md](https://github.com/xushiwei/dex/blob/master/Documentation/using-dex.md)
有了这些 SDK 和 dex 的使用说明,具体 QPaint 业务怎么对接 dex就比较简单了。我们这里就不详细展开详细代码请参考
* [https://github.com/qiniu/qpaint/tree/v44](https://github.com/qiniu/qpaint/tree/v44)
* [https://github.com/qiniu/qpaint/compare/v42...v44](https://github.com/qiniu/qpaint/compare/v42...v44)
## 结语
总结一下今天的内容。
今天我们主要讨论如何基于 OAuth 2.0 来改造 QPaint 的帐号与授权机制。实际上这方面业界有非常成熟的实践,所以我们没有太大的必要去自己重新造一个轮子。我们的核心思路是,基于 [OpenID Connect](https://openid.net/connect/) 协议来提供帐号系统,基于 [OAuth 2.0](https://oauth.net/2/) 协议来实现 Open API 体系。
我们不只是用标准的协议背后的实现也基于开源项目CoreOS 团队开发的 dex。
* [https://github.com/dexidp/dex](https://github.com/dexidp/dex)
这样,我们就可以把关注的重心放在 QPaint 业务本身上。
如果你对今天的内容有什么思考与解读,欢迎给我留言,我们一起讨论。我们服务端程序的实战到这里就要结束了。下一讲聊一聊 “架构:怎么做详细设计” 这个话题。
如果你觉得有所收获,也欢迎把文章分享给你的朋友。感谢你的收听,我们下期再见。