构建OAuth2服务器 Golang语言实现

构建OAuth2服务器~Golang语言实现

前言

自从我和极客时间合作的课程《微服务架构和实践160讲》上线以来,陆续收到一些学员的反馈,包括:

Spring Cloud OAuth2复杂难以理解

OAuth2的四个流程到底是如何实现的?

课程缺乏项目架构设计和实战开发案例

波波老师实践中是如何做架构设计的?

基于学员的上述反馈和疑问,同时考虑到OAuth2是微服务架构的重要环节,我决定带领大家分析一个轻量级OAuth2服务器(项目名Gravitee)的设计和实现,让大家深入理解OAuth2服务的原理和实现,同时解答大家的一些疑问。

我这边的Gravitee项目会使用Golang语言实现,为啥使用Golang呢?原因如下:

Golang语言简单,语法简洁受控,适合课程讲解

Golang由Google公司开发支持,背书强大,社区生态好

Golang语言是云原生基础语言,近年社区热门的开源产品,例如k8s/docker/etcd/istio等,都是使用Golang语言开发

微服务多语言(polygolot)开发的趋势,目前很多互联网公司会同时采用若干种语言开发业务和系统服务,互为补充

OAuth2本身实现和具体语言无关,理解了Golang版代码,不难用其它语言(如Java)实现

注意!!!

本项目代码仅为课程讲解开发,不是生产级!!!如需生产化,则还需要做很多生产扩展+严格的测试,具体见最后的项目扩展环节。同时,你若对本项目做了有价值生产扩展,欢迎提交pull requets到https://github.com/spring2go/gravitee。

本项目源码主要参考RichardKnop的go-oauth2-server[附录1],感谢原作者!本项目对原项目主要做了如下修改:

数据库从postgresql改为mysql

配置简化为使用本地配置文件

依赖更新和使用glide[附录6]管理

架构和设计

总体架构和接口模型

Gravitee总体架构比较简单,使用mysql数据库做存储。数据库之上是数据访问模块,封装数据模型操作。中间层是OAuth2服务模块,这个是Gravitee核心,封装了OAuth2协议的四种核心流程逻辑。顶层有两个接口模块,一个是API模块,对外暴露获取令牌(tokens)和校验令牌(introspect)等端点;另外一个是Web模块,封装涉及Web交互的一些流程,如授权(authorize,授权码模式和简化模式使用),用户注册(register),登录认证(login)和登出(logout)等接口。

数据模型

Gravitee的数据模型也不复杂,核心概念是:

oauth_clients,客户应用

oauth_users,用户或资源拥有者

和三种tokens:

oauth_access_tokens,访问令牌

oauth_authorization_tokens,授权令牌(授权码)

oauth_refresh_tokens,刷新令牌

相关概念和其中的字段本身不难理解,关系也很简单,客户和令牌之间是一对多关系,一个客户应用可以关联很多用户的令牌;用户和令牌之间也是一对多关系,即一个用户使用一个或多个不同应用(client)登陆后,会生成对应的授权码和访问令牌(或+刷新令牌)。

另外还有三个支持表,oauth_roles存储用户角色,oauth_scopes存储作用域相关信息,migrations表支持数据库升级。

波波平时做架构设计,关心的基本上就是:

总体架构,系统的总体架构长啥样?分哪些模块?

接口模型,系统对外暴露哪些接口?主要的输入输出是什么?

数据模型,也称领域模型(domain model),系统的核心概念有哪些?相互关系如何?

波波认为这三者是一个系统的核心抽象,是软件最本质的东西。如果这三者定下来了,那么系统基本就定型了,其它的,比如使用哪种语言实现,使用哪种数据访问层框架等等,都是用来填充的是细节。细节可以不断调整变化,但是本质抽象基本不变(除非架构设计做重大调整)。波波平时做架构设计评审,基本就关注这三样东西,如果一个架构师或者开发lead能把这三样东西讲清楚了,我就评审过,如果讲不清楚,那么不好意思,请回去重新设计。

源码简析

Gravitee的源码不多也不复杂,一般的中高级研发人员不难看懂。我这边再把主要的目录结构梳理一下,方便大家阅读理解源码,见下表:

另外,本项目使用glide[附录6]做依赖管理,使用vscode[附录7]编辑和开发代码。程序的服务结构代码可以参考最简单的健康检查 模块(在health文件夹内),其它的服务模块,如oauth/web/session/user等,都是采用类似的服务结构开发。在 模块中,为了支持登录授权,采用了gorilla session[附录5]做临时状态存储(暂使用客户端session),也采用了golang http的middleware中间件拦截机制,这样登录授权流程才能穿起来,相关逻辑稍复杂,但是也不难看懂。

如果你对Golang还不太熟悉,可以参考go by example[附录8]和go cheat sheet[附录9]快速上手。

安装启动起步

步骤一、下载源码并导入依赖

步骤二、构建服务器

尝试运行服务器,看程序提示信息

程序主要支持migate/loaddata/runserver三个命令。注意,配置文件默认为服务器运行目录中的 文件,如果配置文件在其它目录中,可以使用命令行参数 指定。

步骤三、 创建数据库

安装mysql数据库,创建数据库,例如创建数据库名为 ,然后修改 配置文件中的数据库连接信息,包括数据库名,用户名和密码等。

步骤四、创建表结构

运行

校验数据库中users/clients/tokens等相关表格已经正确创建。注意,migrate动作只需在初始化时做一次。

步骤五、导入一些测试用种子数据

运行

查看users/clients/scopes/roles等表中已经有测试用种子数据

步骤六、运行oauth2服务器

运行

注意,服务器默认启动在8080端口,如需可在配置文件 中修改,上述安装步骤可以同时参考gravitee lab02[附录2]

OAuth2用例实操

下面以授权码模式为例展示如何使用Gravitee OAuth2服务(关于授权码模式的流程规范和请求参数的细节,请参考官方文档[附录3]),假设Gravitee服务器已经启动,端口8080:

步骤一,浏览器授权请求

通过浏览器发起授权码请求:

提示用户登录,可以采用种子用户数据(test@user/test_password)登录:

提示是否授权客户应用(test_client_1)代表用户去访问用户资源:

同意(Allow)授权,则重定向到客户应用指定的redirect_uri(此例是 ),同时会在查询字符串中给出授权码:

如果选择拒绝(Deny),则会提示拒绝授权(access denied)错误。

步骤二,Postman请求令牌

通过Postman(或者curl命令行)模拟客户应用请求令牌,使用上面步骤获取的授权码:

服务器返回访问令牌和刷新令牌:

获取令牌后,客户应用就可以使用该令牌访问用户资源。

其它用例

可以直接参考相应的Gravitee Lab[附录2],或者参考波波的极客时间上的课程视频,其它用例包括:

简化模式

用户名密码模式

客户端模式

令牌校验

令牌刷新

项目扩展环节

注意!!!,本项目代码仅为课程讲解开发,不是生产级!!!如需生产化,则还需要做很多生产扩展+严格的测试,下面是一些可能的扩展点:

支持令牌吊销(token revoke)端点,根据某些业务场景(如用户设备丢失或者恶意用户),可以吊销其令牌。

支持jwt令牌,本项目目前仅支持普通bearer令牌,采用授权服务器集中校验方式验令牌和获取用户信息,可以扩展支持jwt令牌,jwt是自包含令牌(可以包含用户和角色等信息),且是自校验的(不需要集中校验),可实现无状态认证。

Client管理,扩展对客户应用的管理和权限控制

对接企业内部用户数据,目前本项目自带用户模块,实际企业中可能已经有用户数据源,可以考虑和Gravitee服务集成对接。

监控,目前项目暂未实现监控埋点,如生产化前一定要做监控埋点,可以考虑和promethues监控平台对接,有golang客户端可以直接集成。

集中式缓存,目前令牌存mysql数据库,用户访问量不大时OK,如果量大则DB会成为瓶颈,特别是校验令牌操作会频繁发生,此时可以考虑使用内存数据库(如redis等)缓存令牌,加快校验速度。另外目前Web模块使用客户端Session,生产前建议扩展为集中式缓存Session。

高可用,Gravitee本身无状态,生产部署可以水平部署多个,分摊负载和防止单点。

其它语言实现,如果企业暂不能引入golang技术栈,则Gravitee本身很简单,在理解其设计实现的基础上,用其它语言(比如Java)实现并不难。

参考

go-outh2-server(https://github.com/RichardKnop/go-oauth2-server)

Gravitee Lab(https://github.com/spring2go/gravitee_lab)

OAuth2授权框架rfc6749的4.1节(https://tools.ietf.org/html/rfc6749#section-4.1)

gorm(https://github.com/jinzhu/gorm)

gorilla session(github.com/gorilla/sessions)

glide(https://github.com/Masterminds/glide)

vscode(https://code.visualstudio.com/)

go by example(https://github.com/xg-wang/gobyexample)

go cheat sheet(https://github.com/a8m/go-lang-cheat-sheet)

Gravitee项目开源地址(https://github.com/spring2go/gravitee)

微服务架构和实践160讲

  • 发表于:
  • 原文链接:https://kuaibao.qq.com/s/20181211G0X2T700?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券