关于OAuth2.0的那些事儿

说到OAuth2.0,请回忆一下,你是如何登入淘宝,QQ空间,以及微博第三方客户端等等平台的。你会发现它们在登入方便有2个很大的特点

1.是多账户体系共享登入,比如你将你的QQ号与淘宝账号互相绑定,这个时候你在淘宝使用QQ登入也就能自动登入对应绑定的淘宝账户。

2.单点登入(SSO),简单的讲,就是登入状态信任链的事情,共享同一账户的登入状态。比如你在PC上登入了QQ,这个时候你在QQ音乐登入账户的时候,会显示已经登入的QQ号,点击可快速登入。

 

 

关于OAuth2.0的那些事儿-我的技术分享

关于OAuth2.0的那些事儿-我的技术分享关于OAuth2.0的那些事儿-我的技术分享


对于上述第一点就是使用了oauth实现的,第二点使用了SSO实现的,很多人把两者混为一谈,我这里做一下区分。oauth的本质是使用token替代用户名密码,sso是单点登入,也就是一次登入,其他应用畅通无阻。
今天主要讲一下关于oauth的事情。

oauth分1.0和2.0两个版本,2.0不兼容1.0的版本。1.0最初的版本存在严重的安全漏洞,相比1.0,2.0额外提供了多种验证方式,包括授权码、客户端私有证书、资源拥有者密码证书、刷新令牌等

 



从GitHub中抄来的一段解释

 

/**
 *
 * === oauth 2.0
 *  是一种安全验证协议,有很多实现其 oauth 协议的项目,如 spring security oauth2
 *  其授权类型(grant_type)有四种,分布是 authorization_code , implicit , password , client_credentials
 *
 *  主要验证过程:通过身份验证以后,获得 access_token ,access_token 是获得授权的标志。access_token 有有效期,过了有效期,需要重新获取 access_token。
 *
 *  1. authorization_code (或 implicit ,不常用):
 *
 *     第三方网站提供用户身份验证服务。
 *     在 client 在不知道用户名和密码的情况下,通过自己登陆到第三方网站,client 在第三方网站登录成功后,获取到 access_token ,表明已通过身份验证,之后再访问资源服务器内容。
 *     目前这种认证方式是 oauth 的主要用途,如各个网站提供的单点登录功能,就是利用第三方提供的 oauth 的认证,让用户通过第三方的账号,登陆本网站,而网站本身不保留用户的信息。
 *
 *  2. password 和 client_credentials 方式:
 *
 *  2.1  password :
 *     知道了用户名和密码,通过登录 AuthorizationServer 获得 access_token 后,通过 access_token 访问 ResourceServer 资源;
 *
 *  2.2  client_credentials :
 *     client 知道资源的 client_id (也可以是 client_id 和 client_secret),获得 access_token 后,通过access_token 访问资源。
 *
 *     对于这两种种情况,都需要用户向验证服务器提供身份信息,获得 access_token 后,在 access_token 的有效期内,不用再提供身份信息,通过 access_token ,访问资源。
 *
 *  3. 关于信息传递安全
 *     oauth 验证分为两个步骤
 *     1)身份验证,获得 access_token
 *     2)利用 access_token 访问资源服务器(此时不再需要身份信息,access_token 过期后,重新获取)
 *
 *     为了防止传递的信息被截获,
 *     步骤 1) 需要通过 https 协议进行数据传输。https 协议是加密协议,传递的用户身份信息(用户名、密码等)不会被截获。
 *     完成了 1)的身份验证以后,为了提供效率, 2)步骤可以通过 http 协议 ,这是目前大多数网站采取的策略。(2)步骤也可以用 https)
 *
 *  4. 关于开放 API 的安全验证
 *
 *  4.1 采用上文提到的 oauth 方式验证
 *      grant_type=client_credentials 的方式
 *      此种方式,服务器端需要搭建验证服务器(ssh 协议模式)和资源服务器,客户端需要 oauth 客户端技术进行访问。
 *
 *  4.2 利用 HMAC(Hash-based Message Authentication Code 基于散列的消息认证码)
 *
 *
 *
 *  5. 关于生成的 access_token
 *  四种方式生成的 token 和该 client 的相关信息相关:
 *  如用一台电脑的同一浏览器登陆 AuthorizationServer 后,验证成功以后,该电脑的这个浏览器无论以哪种方式,在 token 有效期内不必登陆,直接返回验证成功信息。
 *  登陆一次之后不需要再次登陆,是因为第一次登陆的 token 还没有过期,所以可以继续自动登陆。

 *  如果出现有时验证成功,有时不成功的情况,大多数是因为更改了相关参数,此时删除以后的  token 信息,重新启动电脑即可。
 *
 *  常用的有两种模式
 *  grant_type=client_credentials ,用于对外开放 api
 *  grant_type=authorization_code ,用于单点登录
 *
 *
 *  === oauth2 四种验证方式说明和应用场景 ===
 * 1.  grant_type=authorization_code (重点,常用)
 *
 * 这种验证方式,需要 client 到验证服务器登录页面进行登陆,登陆之后验证服务器保存该 client 的 token
 * -
 * 有的网站引入了第三方登陆方式,登陆一次之后不需要再次登陆,是因为第一次登陆的 token 还没有过期,所以可以继续自动登陆。
 * -
 * 实际应用场景:
 * 单点登录: 不同的第三方应用,用验证服务器统一进行验证登陆,登陆成功之后,返回一个登陆成的 access_token ,表示该用户存在
 * 那么登陆成功后,该 client 的权限信息保存在哪里呢,每个用户的权限不一样,如有的仅有读权限,有的有写权限 ?登陆成功仅能证明该用户存在。
 * 可以有两种模式:
 * - 1) 用户的权限信息保存在验证服务器,可以在登陆成功时,直接返回该用户的权限信息。缺点是,验证服务器上要根据不同的应用,设置不同的用户权限,到底是管理员还是普通用户
 * - 2) 权限信息保存在第三方应用上,这样验证服务器只保证用户存在,不管该用户有什么权限。
 * - 现在看来,应该是 2) 方式,要不然 google 提供的登陆,没办法给那么多的第三方应用分别设置权限了。
 * - 例子:google 开放的登陆,网易新闻保存到有道云笔记等,都会出现一个授权页面,就是该方式的例子。
 * -

 * ------------------------------------------------------------------------------------------------------------------------
 * 2.  grant_type=implicit
 *   该方式没有实验成功,据说是用在 js 中 。
 *   不再尝试该方法,等需要时再看是为什么(google 了半个月的资料,不再试了)。
 *
 * ------------------------------------------------------------------------------------------------------------------------
 *  3.  grant_type=password
 *  该方式需要提供在验证服务器上存在的用户名和密码(如果验证服务器上设置了 client 用户角色信息,则该用户还应该满足角色要求)
 *
 *------------------------------------------------------------------------------------------------------------------------
 *  4.  grant_type=client_credentials (重点,常用)
 *  用于 web 应用向第三方应用提供 api 接口,此时应设置 client_secret ,增加安全性。
 *  典型用例 :
 *  微信 -
 *  微信对公众号提供的接口,就是用了 grant_type=client_credentials 的方式。第三方应用 通过 access_token 来获取相关信息,access_token 的有效期是两个小时(见“微信公众平台开发者文档 / 获取接口凭证 http://mp.weixin.qq.com/wiki/14/9f9c82c1af308e3b14ba9b973f99a8ba.html”)。
 *  对外提供的资源用 get 方法。
 *  不知道微信用的是不是 ouath2 协议,因为 spring ouath2 的 client_credentials 不提供 refresh_token ,而微信的公众号接口提到可以有。
 *  - 所以如果想向外提供 api ,就用此方式。
 *  - 对于每个对外的用户,都单独设置一个 client_id 和 client_secret ,微信的方案是每个用户都有一个。相应限制用户的连接次数,在接收到其发送的查询请求的时候处理,如果通过,在转发到 oauth server。
 */