理解OAuth2
[TOC]json
Oatuh2用来作什么
有这样一种场景,一个用户(假设是QQ),但愿让一个第三方的应用(好比说某个论坛),可以获得关于自身的一些信息(惟一用户标识,好比说QQ号,用户我的信息,好比说是一些基础资料,昵称和头像等)。可是在得到这些资料的同时,却也不能提供用户名和密码之类的验证信息。好比说用户不可能将自身的用户名和密码给第三方让第三方到用户中心之类的地方去获取信息。要达到这样的结果确定有许多的实现方式。而Oatuh2就是实现上述目标的一种规范,或者说是具体实现的指导方案。浏览器
Oauth2具体作法
首先来了解下Oatuh2中的几个名字,方便下文的阐述。安全
- Third-party application: 第三方应用
- Resource Owner: 资源持有者,通常就是用户自身
- Authorization server: 认证服务器
- Resource server: 资源服务器,即具体资源的存储方。与认证服务器是不一样的逻辑节点,可是在物理上,双方是能够在一块儿的
- User Agent: 用户代理,通常就是指的浏览器
- Http Service: 服务提供者,也就是持有Resource Server的存在方。能够理解为相似QQ,或者微信这样具有用户信息的服务者。
Oauth2的做用就是让第三方应用在用户(资源持有者)受权的状况下,经过认证服务器的认证,从而安全的在资源服务器上得到对应的用户资源的流程指导。服务器
Oauth2的流程
Oauth2,根据RFC6749文档,大体的流程以下图所示 微信
上图中的
client就是第三方应用。能够看到,Oauth的大体思路是一个线性的流程。
- 第三方应用向资源持有者请求获取资源
- 资源持有者受权给予第三方应用一个许可
- 第三方应用将该许可给予认证服务器进行认证,若是认证成功,返回一个Access Token
- 第三方应用使用该access token到资源服务器处获取该access token对应的资源(也就是第一步中资源持有者自身的资源)
在上面的这个流程中,其中第二步,资源持有者如何受权给予第三方应用一个许可就是最为关键的地方。其中RFC6749文档给出4种第三方取得受权许可的方式。网络
- 受权码模式
- 简化模式
- 密码模式
- 客户端模式
其中受权码模式是步骤流程最为详细严谨的一种模式。而网络上大部分的第三方Oauth2实现都是基于受权码模式的。本文也是主要讲解受权码模式中的相关流程性问题。至于其余的三种模式,读者能够自行参看RFC6749文档。session
受权码模式
受权码模式的流程以下图所示 app
下面来分别讲解其中的几个点
第三方引导用户跳转至认证服务器的受权页面
在引导跳转的时候须要携带以下的几个参数加密
- response_type:受权类型。受权码模式下,就固定为code
- app_id:第三方应用的标识id。
- redirect_uri:重定向uri,也就是在受权成功后认证服务器让用户重定向的地址。通常而言也就是当前用户在第三方应用中最初的请求地址
- scope:受权范围。可选内容,能够根据第三方应用和实现方的要求自行制定合适的值。
- state:透明的验证参数。RFC6749文档推荐认证服务器在重定向的时候应该原封不一样的返还这个参数。注意,该参数严格来讲应该是一个必须参数。用来防止CSRF攻击。也就是说用于让第三方服务器验证重定向回来的uri的确是认证服务器的行为而不是其余的攻击者伪造的。通常来讲跳转到认证服务器的受权页面是走的https,可是认证服务器重定向到回调地址的时候可能走的就是http。此时code存在泄漏以及url存在被伪造的风险。那么第三方应用必需要有办法验证该回调是否的确由认证服务器发起,而且的确是以前本身的受权请求致使的回调。作法其实也不复杂,就是在session中保存一个随机值,做为state参数。认证服务器回调的时候带上该state参数,第三方应用验证该参数是否与本身session中的state参数值一致便可。若是认证的受权页面不是https加密的,那么在发出请求的时候,认证state参数可能会被窃取。那么这个时候还有另一种作法。也就是第三方应用发送的是加密后的state参数,而认证服务器重定向的时候携带的是解密后的state参数。第三方应用只要在session中判断解密后的值是否与session的一致,也能够达到防止攻击的目的。这样,受权页面也就是能够走在普通的http之中了。
用户选择是否给予受权
这一步是一个用户行为。目前基本的作法都是让用户在受权页面上输入用户名和密码。为了保证安全性,这个页面须要由https来进行保护。固然,若是有其余的方式来保证用户名密码,以及认证的state参数不会泄露也是能够的。若是用户输入正确的用户名和密码,通常就确认为用户给予受权。url
认证服务器生成code而且让用户重定向至指定的url
若是用户给予受权,则认证服务器须要生成一个惟一的受权码code。该code的时效性应该比较短,在5分钟之内比较合适。而且该code只能使用一次,下次就会失效。同时,该code与客户端的id,redirect-uri参数是一一对应的关系。认证服务器此时应该让用户重定向至一开始指定的redirect_uri。携带上state和code参数
第三方应用使用code到认证服务器处兑换令牌access token
第三方应用在验证过state参数的正确性后,接着就可使用code到认证服务器处换取token。这一步,第三方应用须要携带上的参数有
- code:就是认证服务器给予的code参数
- appid:客户端的惟一标识
- redirect_uri:也就是第一步请求中的重定向参数。由于code其实是与appid和redirect_uri一一对应的。因此用code换取令牌的时候也要携带上这两个参数
- grant_type: 受权模式,这里固定为"authorization_code"
- appkey:用于验证应用的身份。appid和appkey能够理解为应用本身的用户名和密码。
oauth2的服务器自己都是走https。因此均可以直接明文传输不须要考虑安全性问题。不过若是不是http的,也能够直接参数用户名密码登陆的方式,就是给appkey进行md5运算。 关于为什么不直接传递accesstoken的问题,是基于安全考虑。由于认证服务器是基于Https,而第三方应用能够是http的。若是在回调的时候直接带上accesstoken,就存在着泄露的问题。
认证服务器返回accesstoken
认证服务器在验证过参数的合法性后,生成一个全局惟一的token,而且返回给第三方应用。返回的内容采用json表示,返回的参数主要有
- access_token: 用于获取对应资源的令牌
- expires_time: 该令牌的有效期
- reflesh_token: 用户获取新的accesstoekn的token。因为accesstoken的有效期比较短,一旦失效,用户须要再走上面的流程是比较繁琐的。为了提高用户体验,可使用reflesh_token来获取新的accesstoken。不过这个作法,已经有不一样的实现方将这个返回参数去掉了。由于实际上reflesh_token也就意味着accesstoekn是永久有效的了。那和直接延长accesstoken的有效期也没有直接区别了。
文章原创首发于公众号:林斌说Java,转载请注明来源,谢谢。
欢迎扫码关注