美文网首页Spring Cloud
OAuth2授权码模式详细流程(一)——站在OAuth2设计者的

OAuth2授权码模式详细流程(一)——站在OAuth2设计者的

作者: 赵召 | 来源:发表于2020-04-14 11:00 被阅读0次

本文来自于公众号链接: OAuth2授权码模式详细流程(一)——站在OAuth2设计者的角度来理解code

[图片上传失败...(image-74c76-1587020454879)])

​本文接上篇公众号文章《OAuth2核心协议概览》

大纲
概述

为什么要有授权模式

站在OAuth2设计者的角度来理解code

第一次实验:OAuth2 Client直接向用户要token
第二次实验:OAuth2 Client在后端直接向AS要token
第三次实验:OAuth2 Client在前端直接向AS要token
第四次实验:OAuth2 Client在前端向AS要code
总结与预告

概述
网上已经有很多介绍OAuth2授权码模式的文章了,也可以参考《最简洁实现Github登录的JS代码示例》。在OAuth2授权码模式流程中有还有很多使人迷惑的细节问题,本文就是回答其中几个与code相关的细节问题,如:
为什么要用户授权后,授权服务器才可以分发token?

为什么要先获取code,再用code交换token,直接获取token不行吗?

code为什么要设计为使用一次就失效?

我们将以全新的视角,站在OAuth2设计者的角度来理解code。
为什么要有授权模式
以《OAuth2核心协议概览》中的“朋友通过小区安保服务去我家里帮我拿东西”的现实场景来类比:
朋友找到小区安保服务,说要去我家拿东西(请求token)

安保电话询问我是否同意。朋友等待结果。

我告诉安保我同意。朋友还在等待结果。

安保挂断电话,允许朋友进入我家(获取到token)。

那OAuth2也完全照抄这个流程不就行了?就像这样:

可是关键的问题在于,web系统与现实场景是有区别的:
在web系统中,第一步请求token后,网络链接就关闭了,无法等待第四步token的返回。而一旦断开连接,Authorization Server就再也无法主动找到到OAuth2 Client,更不可能把token给到到OAuth2 Client了 。

web系统与现实生活例子最大区别就是web系统无法长时间等待:

Http协议是单向的无状态协议。只有浏览器端主动连接到服务器端,而服务器端是无法主动找到浏览器端的。

web系统的服务端要要同时支持无数浏览器端高并发,因此常规的Http的请求都是有超时限制的短链接,长时间不响应就会主动断开链接。

现实中获取token的流程不适合web系统,那么OAuth2协议是通过怎样的流程来绕过Http协议B/S架构的局限性,从而实现安全且相对高效地获取token的呢?
OAuth2把如何获取授权,从而获取token的这套流程称为“授权模式”。而其中最通用、最安全的流程叫做“授权码模式”。
站在OAuth2设计者的角度来理解授权码模式中的code
先不管OAuth2授权码模式详细流程是什么,我们假设自己就是OAuth2的设计者,现在要自己想办法实现安全、高效地获取token。
首先整个业务场景有四个角色:

Authorization Server认证服务器,简称AS

Resource Server资源服务器,简称RS

OAuth2 Client客户端,其他第三方服务

Resource Owner/User agent用户/用户代理,浏览器

其中的AS、RS和OAuth2 Client是web系统,而且OAuth2 Client和AS都必须有后端和前端。
我们要解决的是OAuth2 Client客户端如何获取token,然后使用这个token请求资源的问题。

第一次实验:OAuth2 Client直接向用户要token
是不是我们把问题想复杂了,OAuth2 Client 客户端直接跟用户要token不行吗?就像这样:

当然是不行的。用户哪里来的token?用户只有用户名和密码,而且是不能给你的。

第二次实验:OAuth2 Client在后端直接向AS要token
既然用户没有token,token是由AS颁发的,那最简单的方案不就是是那OAuth2 Client后端直接http请求AS的后端要token吗?就像这样:

这种流程也明显是不行的,因为AS首先要通知到用户,由用户亲自授权后,AS才能向OAuth2 Client发token。不经过用户授权就随便发token是明显地侵犯他人权益,不允许。
第三次实验:OAuth2 Client在前端直接向AS要token
那第一步请求获取token的操作就只能由OAuth2 Client的前端来发起了。
就像这样:

OAuth2 Client前端请求AS

AS返回一个交互页面,让用户确认是否授权

用户授权

到此AS已经获取到了用户授权,AS可以颁发token了。
此时面临的新问题是:AS如何把token给到OAuth2 Client?

经过分析,我只想到了两种方式:

方式一:直接给前端。虽然此时网络链接已经断开,但是AS仍然可以通过浏览器重定向的方式,将token作为URL参数传给到OAuth2 Client的前端。

方式二:直接给后端。AS直接调用OAuth2 Client后端的接口将token给到后端。但是先不说AS是否能直接调用 OAuth2 Client后端接口,就算可以调用, OAuth2 Client的后端也无法简单快捷地把获取token成功的状态通知到 OAuth2 Client前端和用户。

所以我们选择第一条路,通过浏览器重定向的方式将token给到 OAuth2 Client前端,OAuth2 Client前端再把token给OAuth2 Client后端就行了。
第四次实验:OAuth2 Client在前端向AS要code
虽然经过第三次实验后,OAuth2 Client 拿到了token。
可此时面临的新问题是:token直接暴露在浏览器地址栏了。
泄露token意味着直接泄露资源服务器中的数据。换句话说,token不应该出现在前端的任何地方。token只能在OAuth2 Client 、AS 和RS后端之间传递。

我实在想不出如何解决这个问题,但是OAuth2解决这个问题的方式非常巧妙,那就是引入code,这个code被称作“授权码”,这就是"授权码模式"名称的由来。具体的流程如图:

浏览器重定向不直接传token,而是先传一个code

OAuth2 Client前端拿到code,传给OAuth2 Client后端

OAuth2 Client后端携带这个code调用AS后端,AS校验成功后,放心地分发token。

为了安全,每一个code只能使用一次:AS一旦接收到携带这个code的请求,那这个code就作废了,不能使用同一个code再次请求了。同时,携带code交换token时,请求参数中需要携带OAuth2 Client的密钥。对于黑客来说,同一个code只能使用一次,还无法获取OAuth2 Client密钥,也就无法做token的暴力碰撞了。最重要的是:token一直在后端之间传递,根本就不给黑客通过浏览器窥视token的机会。

至此这就是完整的授权码模式流程。为什么要引入code来交换token的问题也就迎刃而解了。
总结与预告
OAuth2授权码模式完整流程图:

道高一尺魔高一丈,安全不是绝对的。假如token真的泄露了,那也比直接泄露用户名和密码强。因为:
token是有效期的,并且一般有效期很短,几秒钟到几分钟,短期的,到期就自动失效。

token可以被用户主动撤销而失效

token可以访问的数据是有权限控制的,是有限的权限。

这些OAuth2的细节设计都进一步增强了OAuth2协议的安全性。OAuth2协议也是非常灵活的协议,为了适应各种复杂的应用场景,除了授权码模式外,OAuth2还支持其他的授权模式,如密码模式、客户端模式和隐式授权码模式等等。另外授权码模式本身也还有很多细节问题,比如:
授权码模式中的scope到底都哪些用处,实现逻辑是怎样?

刷新token的逻辑怎么写才是正确的?

浏览器可以直接调用“/oauth/token”来获取token吗?为什么?

为什么一般的授权服务器的token接口都是禁止跨源访问的?

client_secret在获取code阶段需要传吗?

state参数到底有什么用,防止了哪些安全问题?

token本身是一个字符串,字符串本身可以是json格式数据吗?

token的有效期多长时间合适呢?

如何管理token的生命周期,token的格式是什么?

等等等等

这些话题都会在后续的文章里来讲解。
参考
OAuth2核心协议RFC 6749

更多干货都在《spring security实战》

本文来自于公众号链接: 彻底理解浏览器同源策略SOP
[图片上传失败...(image-b36771-1587020454879)])

本文由博客群发一文多发等运营工具平台 OpenWrite 发布

相关文章

网友评论

    本文标题:OAuth2授权码模式详细流程(一)——站在OAuth2设计者的

    本文链接:https://www.haomeiwen.com/subject/hzrzmhtx.html