天天看點

oauth 手寫_手寫oauth2.0(附mysql表設計與具體互動流程)

鉴于 spring security 与 oauth2.0标准过于繁琐,为方便理解与实际实现,故手写其实现。

1、oauth2.0介绍

OAuth 2.0的运行流程如下图,摘自RFC 6749。

oauth 手寫_手寫oauth2.0(附mysql表設計與具體互動流程)

(A)用户打开客户端以后,客户端要求用户给予授权。

(B)用户同意给予客户端授权。

(C)客户端使用上一步获得的授权,向认证服务器申请令牌。

(D)认证服务器对客户端进行认证以后,确认无误,同意发放令牌。

(E)客户端使用令牌,向资源服务器申请获取资源。

(F)资源服务器确认令牌无误,同意向客户端开放资源。

1.1、oauth2.0-授权码模式介绍

oauth 手寫_手寫oauth2.0(附mysql表設計與具體互動流程)

(A)用户访问客户端,后者将前者导向认证服务器。

(B)用户选择是否给予客户端授权。

(C)假设用户给予授权,认证服务器将用户导向客户端事先指定的"重定向URI"(redirection URI),同时附上一个临时授权码。

(D)客户端收到临时授权码,附上早先的"重定向URI",向认证服务器申请令牌。这一步是在客户端的后台的服务器上完成的,对用户不可见。

(E)认证服务器核对了临时授权码和重定向URI,确认无误后,向客户端发送访问令牌(access token)。

1.2、oauth2.0-密码模式介绍

oauth 手寫_手寫oauth2.0(附mysql表設計與具體互動流程)

(A)用户向客户端提供用户名和密码。

(B)客户端将用户名和密码发给认证服务器,向后者请求令牌。

(C)认证服务器确认无误后,向客户端提供访问令牌。

2、逻辑交互

以某个**监测服务(web端)**为例,尝试登陆公司的SSO账户。

2.1、授权码模式实现

2.1.1、表结构设计

DROP TABLE IF EXISTS `sys_oauth_client`;

CREATE TABLE `sys_oauth_client` (

`client_id` varchar(50) NOT NULL COMMENT '客户端id',

`client_name` varchar(256) DEFAULT NULL COMMENT '应用名',

`client_secret` varchar(256) DEFAULT NULL COMMENT '应用密钥',

`client_redirect_uri_host` varchar(256) DEFAULT NULL COMMENT '对应主机域名',

`status` int(1) DEFAULT NULL COMMENT '状态。0:正常;1:冻结',

`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',

`update_time` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',

PRIMARY KEY (`client_id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用client表';

BEGIN;

INSERT INTO `sys_oauth_client` VALUES ('joe_monitoring', '监测服务(web端)', 'admin123', '','0', '2018-08-30 19:42:32', '2018-08-30 20:24:08');

COMMIT;

DROP TABLE IF EXISTS `sys_oauth_user_authorize`;

CREATE TABLE `sys_oauth_user_authorize` (

`id` int(20) NOT NULL AUTO_INCREMENT,

`client_id` varchar(50) NOT NULL COMMENT '客户端id',

`oauth_user_id` varchar(50) NOT NULL COMMENT '绑定账号的id,例如对应wx来说,就是openId',

`user_id` int(11) NOT NULL COMMENT '对应user_id',

`oauth_user_name` varchar(50) DEFAULT '' COMMENT '绑定账号的名称',

UNIQUE KEY `Unique_client_idAnduser_id` (`client_id`,`user_id`) USING BTREE,

UNIQUE KEY `Unique_client_idAndoauth_user_id` (`client_id`,`oauth_user_id`) USING BTREE,

KEY `id` (`id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='账号授权表'

技术选型上:springcloud 全家桶

2.1.2、各个服务

认证与授权服务:joe-sso,即SSO服务

用户、权限管理服务: joe-admin

api资源服务: joe-resource

静态文本资源(css、js、img等)服务:joe-file

监测服务:joe-client-monitoring

另:

注册中心:joe-eureka

网关:joe-zuul

2.1.3、名词解释

客户端:这里指代 监测服务(web端); 其对应的client_id,在库中为joe_monitoring

认证服务器: 这里指代 joe-oauth服务

重定向URI: 即下文中的 redirect_uri字段

临时授权码:即下文中的 temp_authorize_code字段

访问令牌:即下文中的 accessToken字段

3、接口请求

3.1、监测服务(web端)获取自身的client_id

GET请求,接口: joe-client-wechat/client/clientId 返回示例:

{

"status": 0,

"msg": "成功。",

"data": "joe_monitoring"

}

3.2、前端跳转到登陆页面,并传递过来参数

传递参数(以web浏览器为例,将其以get传参的形式,暴露在地址栏中):

参数

示例

说明

client_id

joe_monitoring

客户端id

eg:实际传递请求uri

解释:

passport.joe.com :joe-sso服务地址

/authorize/login: 授权码模式登陆接口

正常情况下,oauth2.0模式下,授权码模式,字段释义:

response_type:表示授权类型,必选项,此处的值固定为"code"

client_id:表示客户端的ID,必选项

redirect_uri:表示重定向URI,可选项

scope:表示申请的权限范围,可选项

state:表示客户端的当前状态,可以指定任意值,认证服务器会原封不动地返回这个值。

eg,在新浪微博中,采用360账号登陆,跳转的url为:

分析:上述uri,显然为oauth2.0模式下的授权码登陆模式。

3.3、登陆页面的登陆

GET请求,接口: joe-sso/oauth/authorize/login

即 SSO账户系统的登陆系统下的“登陆”按钮

传递参数:

参数

示例

说明

client_id

joe_monitoring

客户端id

login_name

admin

用户名

password

admin

密码

若登陆成功,返回 temp_authorize_code临时授权码 :

{

"status": 0,

"msg": "成功。该临时授权码有效期为10分钟",

"data": {

"temp_authorize_code": "joe_monitoring:28115fff54884bc0800442ffb51a3f98"

}

}

其他错误情况:

{

"status": 20,

"msg": "失败。joe-sso认证失败,请检查client_id的准确性,或该client_id已被冻结",

"data": null

}

{

"status": 30,

"msg": "失败。登陆名或密码错误,用户不存在",

"data": null

}

获取到 临时授权码temp_authorize_code后,登陆页面前端跳转链接回监测服务(web端)(通过redirect_uri)

注意:该temp_authorize_code存储在redis中,设置好过期时间。

3.4、监测服务(web端)尝试向joe_sso获取accessToken

上一步,我们获取到temp_authorize_code。现在,将temp_authorize_code发送给SSO服务,从而获取accessToken。

监测服务(web端)前端通过跳转回的浏览器地址栏,获取到对应到temp_authorize_code后,发送GET请求到监测服务(web端)的后端,接口: joe-client-monitoring/client/accessToken

监测服务(web端)的后端,将会添加自己的client_id、client_secret参数,一起通过http发送给joe-sso账户服务,获取accessToken。

参数

示例

说明

client_id

joe_monitoring

客户端id

client_secret

admin123

客户端密钥

temp_authorize_code

joe_monitoring:52d1595aeba64b4fa087c9c96ab42bb2

临时授权码

eg:实际传递请求uri

返回结果:

{

"status":0,

"msg":"成功。该access_token有效期为120分钟,下次请求将重置有效期",

"data":"joe_monitoring:d29d492c678640a6b3952c4fb0dc24be"

}

该accessToken有效期120分钟,后续每次请求会重置有效期(类似session的功能)。后期考虑添加:超时1天后,强制失效重新登陆的功能。

注意:

该获取accessToken存储在redis中,设置好过期时间。

监测服务(web端)需要将对应的 accessToken 自行存储起来(jvm cache或 redis中均可)。

注意:该请求过程,对于用户来说,是无感知的。

至此,授权服务已基本完成。

3.5、微信客户端获取用户信息 by accessToken

GET请求,接口: joe-sso/oauth/userInfo

传递参数:

http的header中添加joe_access_token,即

参数

示例

说明

joe_access_token

joe_monitoring:52d1595aeba64b4fa087c9c96ab42bb2

即第3.4步骤中,微信客户端尝试获取的accessToken

返回结果:

{

"status": 0,

"msg": "成功。",

"data": {

"create_time": "2018-09-11 10:16:12",

"user_id": 1,

"user_name": "admin",

"user_nick_name": "我是用户昵称joe",

"redirect_uri": "http://localhost:9000/callback"

}

}

其他

源码

文中所述功能均已实现。具体代码,后期将视情况发布至github上。地址为:github仓库地址

参考链接: