1. 简介
- 快递员的例子:OAuth 2.0 的一个简单解释
- OAuth2.0 是目前最流行的授权机制
- 用来授权第三方应用(向第三方应用颁发令牌),获取用户数据
- 数据的所有者告诉系统,同意授权第三方应用进入系统,获取这些数据
- 系统从而产生一个短期的进入令牌(token),用来代替密码,供第三方应用使用
2. OAuth 2.0 的验证方式
- 参考文章:OAuth 2.0 的四种方式
- 不管哪一种授权方式,第三方应用申请令牌之前,都必须先到系统备案,说明自己的身份
- 然后会拿到两个身份识别码:客户端 ID(client ID)和客户端密钥(client secret)
2.1. 授权码(authorization-code)
- 第三方应用先申请一个授权码,然后再用该码获取令牌
- 是最常用的流程,安全性最高,适用于那些有后端的Web应用
- 授权码通过前段传送,令牌是存储在后端,而且所有与资源服务器的通信都在后端完成
- 这样前后端分离,可以避免令牌泄露
- 流程
- A网站请求授权码
- B网站返回授权码
- A网站在后端请求令牌
- B网站返回令牌(向redirect_uri指定的网址,发送一段 JSON 数据)
2.2. 隐藏式(implicit)
- 适用于Web应用是纯前端的,必须将令牌储存在前端,即直接向前端办法令牌,没有授权码这个中间步骤
- 这种方式把令牌直接传给前端,是很不安全的
- 只能用于一些安全要求不高的场景,并且令牌的有效期必须非常短,通常就是会话期间(session)有效
- 流程
- A网站请求授权码
- B网站返回令牌(将令牌作为URL参数,传给A网站
https://a.com/callback#token=ACCESS_TOKEN
) - 令牌的位置是 URL锚点(fragment),而不是查询字符串(querystring)
- 因为 OAuth 2.0 允许跳转网址是 HTTP协议,因此存在"中间人攻击"的风险
- 而浏览器跳转时,锚点不会发到服务器,就减少了泄漏令牌的风险
- 锚点介绍参考:URI's fragment
2.3. 密码式(password / resource owner password credentials)
- 如果你高度信任某个应用,RFC 6749 也允许用户把用户名和密码,直接告诉该应用
- 该应用就使用你的密码,申请令牌
- 这种方式需要用户给出自己的用户名/密码,显然风险很大
- 只适用于其他授权方式都无法采用的情况,且必须是用户高度信任的应用
- 流程
- 用户提供B网站的用户名密码
- A网站带着用户名密码直接向B网站请求令牌
- B网站通过身份验证后,直接给令牌(放在JSON数据里,作为HTTP回应)
2.4. 客户端凭证(client credentials)
- 适用于没有前端的命令行应用,即在命令行下请求令牌
- 这种方式给出的令牌,是针对第三方应用的,而不是针对用户的,即有可能多个用户共享同一个令牌
- 流程
- A应用在命令行向B发送请求
- B网站通过验证以后,直接返回令牌
2.5. 令牌使用与更新
- 具体做法是在请求的头信息,加上一个Authorization字段,令牌就放在这个字段里面
- 令牌到期后,再走一遍申请流程,很可能体验不好,而且没有必要
- Oauth 2.0允许用户自动更新令牌,更新方法如下:
- B网站颁发令牌的时候,一次性颁发两个令牌
- 一个用于获取数据,另一个用于获取新的令牌(refresh token)
- 令牌到期前,用户使用 refresh token 发一个请求,去更新令牌
/oauth/token?grant_type=refresh_token&refresh_token=REFRESH_TOKEN
3. GitHub OAuth 第三方登录(授权码模式)
- 参考文章:GitHub OAuth 第三方登录示例教程
- 其他示例:微信第三方登录(授权码模式)
3.1. 第三方登录原理
- A 网站让用户跳转到 GitHub
- GitHub 要求用户登录,然后询问 " A 网站要求获得 xx 权限,你是否同意?"
- 用户同意,GitHub 就会重定向回 A 网站,同时发回一个授权码
- A 网站使用授权码,向 GitHub 请求令牌
- GitHub 返回令牌
- A 网站使用令牌,向 GitHub 请求用户数据
3.2. 应用登记
- 一个应用要求OAuth授权,必须先到对方网站登记,让对方知道是谁在请求
- 提交表单以后,GitHub 应该会返回客户端 ID和客户端密钥,这就是应用的身份识别码
3.3. 浏览器跳转Github
- 跳转的URL如下
…/github.com/login/oauth/authorize?client_id=7e015d8ce32370079895&redirect_uri=…/localhost:8080/oauth/redirect
- 这个 URL 指向 GitHub 的 OAuth 授权网址,带有两个参数
- client_id告诉 GitHub 谁在请求
- redirect_uri是稍后跳转回来的网址
- 用户点击到了 GitHub,GitHub 会要求用户登录,确保是本人在操作
3.4. 授权码
- 登录后,GitHub询问用户,该应用在请求授权,是否同意授权
- 用户同意授权, GitHub会跳转大到redirect_uri指定的跳转网站,并带上授权码
- 跳转回来的URL是下面这个样子
…/localhost:8080/oauth/redirect?code=859310e7cecc9196f4af
- 后端收到这个请求以后,就拿到了授权码
3.5. 令牌
- 后端使用这个授权码,向Github请求令牌
- 作为回应,Github会返回一段JSON数据,里面包含了令牌accessToken
3.6. API数据
- 有了令牌之后,就可以向API请求数据了
- 请求的时候,必须在HTTP头信息里面打上令牌
Authorization: token 361507da
4. 理解Oauth 2.0
- 参考文章:理解OAuth 2.0
- OAuth在"客户端"与"服务提供商"之间,设置了一个授权层(authorization layer)
- "客户端"不能直接登录"服务提供商",只能登录授权层,以此将用户与客户端区分开来
- "客户端"登录授权层所用的令牌(token),与用户的密码不同
- 用户在登录的时候,指定授权层令牌的权限范围和有效期
- "客户端"登录授权层以后,"服务提供商"根据令牌的权限范围和有效期,向"客户端"开放用户储存的资料
- 运行流程
- 用户打开客户端以后,客户端要求用户给予授权
- 用户同意给予客户端授权
- 客户端使用上一步获得的授权,向认证服务器申请令牌
- 认证服务器对客户端进行认证以后,确认无误,同意发放令牌
- 客户端使用令牌,向资源服务器申请获取资源
- 资源服务器确认令牌无误,同意向客户端开放资源
- 客户端授权模式
- 客户端以自己的名义,而不是以用户的名义,向"服务提供商"进行认证
- 严格地说,客户端模式并不属于OAuth框架所要解决的问题
- 在这种模式中,用户直接向客户端注册
- 客户端以自己的名义要求"服务提供商"提供服务,不存在授权问题