鉴于 spring security 与 oauth2.0标准过于繁琐,为方便理解与实际实现,故手写其实现。css
如下部分参考自理解OAuth 2.0 - 阮一峰的网络日志html
OAuth 2.0的运行流程以下图,摘自RFC 6749。 前端
(A)用户打开客户端之后,客户端要求用户给予受权。 (B)用户赞成给予客户端受权。 (C)客户端使用上一步得到的受权,向认证服务器申请令牌。 (D)认证服务器对客户端进行认证之后,确认无误,赞成发放令牌。 (E)客户端使用令牌,向资源服务器申请获取资源。 (F)资源服务器确认令牌无误,赞成向客户端开放资源。
(A)用户访问客户端,后者将前者导向认证服务器。 (B)用户选择是否给予客户端受权。 (C)假设用户给予受权,认证服务器将用户导向客户端事先指定的"重定向URI"(redirection URI),同时附上一个临时受权码。 (D)客户端收到临时受权码,附上早先的"重定向URI",向认证服务器申请令牌。这一步是在客户端的后台的服务器上完成的,对用户不可见。 (E)认证服务器核对了临时受权码和重定向URI,确认无误后,向客户端发送访问令牌(access token)。
(A)用户向客户端提供用户名和密码。 (B)客户端将用户名和密码发给认证服务器,向后者请求令牌。 (C)认证服务器确认无误后,向客户端提供访问令牌。
以某个**监测服务(web端)**为例,尝试登录公司的SSO帐户。git
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
全家桶github
joe-sso
,即SSO服务joe-admin
joe-resource
joe-file
joe-client-monitoring
另:web
joe-eureka
joe-zuul
client_id
,在库中为joe_monitoring
joe-oauth
服务redirect_uri
字段temp_authorize_code
字段accessToken
字段监测服务(web端)
获取自身的client_id
GET
请求,接口: joe-client-wechat/client/clientId
返回示例:redis
{ "status": 0, "msg": "成功。", "data": "joe_monitoring" }
登录
页面,并传递过来参数参数 | 示例 | 说明 |
---|---|---|
client_id | joe_monitoring | 客户端id |
redirect_uri | http://localhost:9000/callback | 需重定向的uri |
eg:实际传递请求uri
spring
解释:后端
passport.joe.com
:joe-sso
服务地址/authorize/login
: 受权码模式登录接口正常状况下,oauth2.0模式下,受权码模式,字段释义:api
response_type:表示受权类型,必选项,此处的值固定为"code" client_id:表示客户端的ID,必选项 redirect_uri:表示重定向URI,可选项 scope:表示申请的权限范围,可选项 state:表示客户端的当前状态,能够指定任意值,认证服务器会原封不动地返回这个值。
eg,在新浪微博中,采用360帐号登录,跳转的url为:
分析:上述uri,显然为oauth2.0模式下的受权码登录模式。
登录
页面的登录GET
请求,接口: joe-sso/oauth/authorize/login
即 SSO帐户系统的登录系统下的“登录”按钮
参数 | 示例 | 说明 |
---|---|---|
client_id | joe_monitoring | 客户端id |
redirect_uri | http://localhost:9000/callback | 需重定向的uri |
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
中,设置好过时时间。
监测服务(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。
对应接口joe-sso帐户服务
的获取accessToken接口为:http://passport.joe.com/authorize/accessToken
参数 | 示例 | 说明 |
---|---|---|
client_id | joe_monitoring | 客户端id |
client_secret | admin123 | 客户端密钥 |
redirect_uri | http://localhost:9000/callback | 需重定向的uri,和上一步骤一致 |
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中都可)。注意:该请求过程,对于用户来讲,是无感知的。
至此,受权服务已基本完成。
微信客户端
获取用户信息 by accessTokenGET
请求,接口: 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仓库地址