Skip to content
go语言实现的轻量级oauth2服务器
Go HTML CSS
Branch: master
Clone or download
william's mac
Latest commit 9e2453e Feb 2, 2019
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
cmd minor fix Nov 28, 2018
config support create user endpoint Nov 27, 2018
database init commit Nov 23, 2018
health init commit Nov 23, 2018
images
log init commit Nov 23, 2018
models fix mysql strict mode issue Feb 2, 2019
oauth fix username issue Nov 23, 2018
public/css
services support create user endpoint Nov 27, 2018
session
test-util init commit Nov 23, 2018
user minor fix Nov 28, 2018
util init commit Nov 23, 2018
web
.gitignore fix mysql strict mode issue Feb 2, 2019
LICENSE Initial commit Nov 23, 2018
README.md add project logo Dec 11, 2018
config.yml minor fix Nov 28, 2018
glide.lock init commit Nov 23, 2018
glide.yaml init commit Nov 23, 2018
gravitee-server.go

README.md

Gravitee OAuth2简介

gravitee oauth2

Go语言实现的轻量级OAuth2服务器,为极客时间课程《微服务架构和时间160讲》而开发。

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

  • Spring Cloud OAuth2复杂难以理解
  • OAuth2的四个流程到底是如何实现的?
  • 课程缺乏项目架构设计和实战开发案例
  • 波波老师实践中是如何做架构设计的?

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

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

  1. Golang语言简单,语法简洁受控,适合课程讲解
  2. Golang由Google公司开发支持,背书强大,社区生态好
  3. Golang语言是云原生基础语言,近年社区热门的开源产品,例如k8s/docker/etcd/istio等,都是使用Golang语言开发
  4. 微服务多语言(polygolot)开发的趋势,目前很多互联网公司会同时采用若干种语言开发业务和系统服务,互为补充
  5. OAuth2本身实现和具体语言无关,理解了Golang版代码,不难用其它语言(如Java)实现

注意!!!

  1. 本项目代码仅为课程讲解开发,不是生产级!!!如需生产化,则还需要做很多生产扩展+严格的测试,具体见项目扩展环节。同时,你若对本项目做了有价值生产扩展,欢迎提交pull requets。
  2. 本项目源码主要参考RichardKnop的go-oauth2-server,感谢原作者!本项目对原项目主要做了如下修改:
  • 数据库从Postgresql改为Mysql
  • 配置简化为使用本地配置文件
  • 依赖更新和使用glide管理

安装启动起步

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

glide install

步骤二、构建服务器

go build gravitee-server.go

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

./gravitee-server

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

步骤三、 创建数据库

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

步骤四、创建表结构

运行

./gravitee-server migrate

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

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

运行

./gravitee-server loaddata oauth/fixtures/scopes.yml oauth/fixtures/roles.yml oauth/fixtures/test_clients.yml oauth/fixtures/test_users.yml

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

步骤六、运行oauth2服务器

运行

./gravitee-server runserver 

注意,服务器默认启动在8080端口,如需可在配置文件config.yml中修改,上述安装步骤可以同时参考Gravitee Lab

OAuth2用例实操

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

步骤一,浏览器授权请求

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

http://localhost:8080/web/authorize?client_id=test_client_1&redirect_uri=https://www.example.com&response_type=code&state=somestate&scope=read_write

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

login

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

authorize

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

redirect

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

步骤二,Postman请求令牌

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

curl -X POST --user test_client_1:test_secret http://localhost:8080/v1/oauth/tokens -d "code=c88f0354-6cd4-4f4e-ac2f-ffa5bf4c97fb&grant_type=authorization_code&redirect_uri=https://www.example.com&scope=read_write"

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

postman

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

其它用例

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

  • 简化模式
  • 用户名密码模式
  • 客户端模式
  • 令牌校验
  • 令牌刷新

架构和设计

总体架构和接口模型

arch

intf

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

数据模型

data

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

  • oauth_clients,客户应用
  • oauth_users,用户或资源拥有者

和三种tokens:

  • oauth_access_tokens,访问令牌
  • oauth_authorization_tokens,授权令牌(授权码)
  • oauth_refresh_tokens,刷新令牌

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

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

源码简析

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

主要目录和文件 简析
cmd 一些命令入口文件,如导入种子数据,数据库升级(包括第一次创建数据库表)和启动服务器
config 服务器配置相关支持类,配置有数据库配置、OAuth2服务配置和Session相关配置等
database 负责建立和获取数据库连接的支持文件
health 暴露健康检查端点的服务
log 日志相关支持类
models 数据模型和ORM(使用gorm)相关支持文件,OAuth2核心数据模型在这里
oauth 封装OAuth2的核心流程逻辑,并暴露服务接口和HTTP端点,这是最复杂的一个文件夹
public 静态css文件
services 服务初始化和入口文件,类似一个service registry
session Web Session相关的服务封装支持类
test-util 测试相关支持类
user 暴露用户创建端点的服务
util 项目中用到的工具类
vendor 第三方依赖包,由glide依赖工具导入
web web模块的实现类,支持授权、注册、登录和登出的Web流程逻辑,同时依赖OAuth2Session模块提供的服务
gravitee-server.go 服务器程序主入口(main),使用cmd目录内的命令执行具体任务。

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

另外,本项目使用glide做依赖管理,使用vscode编辑和开发代码。

如果你对Golang还不太熟悉,可以参考go by examplego cheat sheet快速上手。

项目扩展环节

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

  1. 支持令牌吊销(token revoke)端点,根据某些业务场景(如用户设备丢失或者恶意用户),可以吊销其令牌。
  2. 支持jwt令牌,本项目目前仅支持普通bearer令牌,采用授权服务器集中校验方式验令牌和获取用户信息,可以扩展支持jwt令牌,jwt是自包含令牌(可以包含用户和角色等信息),且是自校验的(不需要集中校验),可实现无状态认证。
  3. Client管理,扩展对客户应用的管理和权限控制
  4. 对接企业内部用户数据,目前本项目自带用户模块,实际企业中可能已经有用户数据源,可以考虑和Gravitee服务集成对接。
  5. 监控,目前项目暂未实现监控埋点,如生产化前一定要做监控埋点,可以考虑和promethues监控平台对接,有golang客户端可以直接集成。
  6. 集中式缓存,目前令牌存mysql数据库,用户访问量不大时OK,如果量大则DB会成为瓶颈,特别是校验令牌操作会频繁发生,此时可以考虑使用内存数据库(如redis等)缓存令牌,加快校验速度。另外目前Web模块使用客户端Session,生产前建议扩展为集中式缓存Session。
  7. 高可用,Gravitee本身无状态,生产部署可以水平部署多个,分摊负载和防止单点。
  8. 其它语言实现,如果企业暂不能引入golang技术栈,则Gravitee本身很简单,在理解其设计实现的基础上,用其它语言(比如Java)实现并不难。

参考

《微服务架构实战160讲》

微服务架构实战160讲

You can’t perform that action at this time.