手写oauth2.0(附mysql表设计与具体交互流程)

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

1、oauth2.0介绍

以下部分参考自理解OAuth 2.0 - 阮一峰的网络日志

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

(A)用户打开客户端以后,客户端要求用户给予授权。
(B)用户同意给予客户端授权。
(C)客户端使用上一步获得的授权,向认证服务器申请令牌。
(D)认证服务器对客户端进行认证以后,确认无误,同意发放令牌。
(E)客户端使用令牌,向资源服务器申请获取资源。
(F)资源服务器确认令牌无误,同意向客户端开放资源。

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

image

(A)用户访问客户端,后者将前者导向认证服务器。 
(B)用户选择是否给予客户端授权。 
(C)假设用户给予授权,认证服务器将用户导向客户端事先指定的"重定向URI"(redirection URI),同时附上一个临时授权码。 
(D)客户端收到临时授权码,附上早先的"重定向URI",向认证服务器申请令牌。这一步是在客户端的后台的服务器上完成的,对用户不可见。 
(E)认证服务器核对了临时授权码和重定向URI,确认无误后,向客户端发送访问令牌(access token)。

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

image

(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_idjoe_monitoring客户端id
redirect_urihttp://localhost:9000/callback需重定向的uri

eg:实际传递请求uri

解释:

  • passport.joe.comjoe-sso服务地址
  • /authorize/login: 授权码模式登陆接口

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

response_type:表示授权类型,必选项,此处的值固定为"code"
client_id:表示客户端的ID,必选项
redirect_uri:表示重定向URI,可选项
scope:表示申请的权限范围,可选项
state:表示客户端的当前状态,可以指定任意值,认证服务器会原封不动地返回这个值。

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

https://openapi.360.cn/oauth2/authorize?client_id=8819d1babbbc50a42021ee957c4b6e63&response_type=code&redirect_uri=https://account.weibo.com/set/bindsns/callback&scope=basic&display=default&state=360&relogin=sina

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

3.3、登陆页面的登陆

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

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

  • 传递参数:
参数示例说明
client_idjoe_monitoring客户端id
redirect_urihttp://localhost:9000/callback需重定向的uri
login_nameadmin用户名
passwordadmin密码
  • 若登陆成功,返回 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_idclient_secret参数,一起通过http发送给joe-sso账户服务,获取accessToken。

对应接口joe-sso账户服务的获取accessToken接口为:http://passport.joe.com/authorize/accessToken

参数示例说明
client_idjoe_monitoring客户端id
client_secretadmin123客户端密钥
redirect_urihttp://localhost:9000/callback需重定向的uri,和上一步骤一致
temp_authorize_codejoe_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

  • 传递参数:

httpheader中添加joe_access_token,即

参数示例说明
joe_access_tokenjoe_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仓库地址

参考链接:

转载于:https://my.oschina.net/u/3136014/blog/2243716

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值