Posted on:
Last modified:
今天有个项目需要用到 OAuth2 来处理一些东西,然而中文互联网有时候真是很难找到像样的文档, 搜索 “OAuth 教程” 的到排名前两位的 教 程 都是翻译自一个英文教程,翻译质量奇差 无比就不说了,这个英文教程本身就是有问题的,无奈只好搜索 “OAuth tutorial” 才找到几个看得 过去的英文教程,总结一下放在这里,算是为中文互联网引入一些正确的知识。
看到 OAuth2 这个词,一般人肯定会想,是不是还有个 OAuth 1 协议呢?是的,有 OAuth 1 协议, 但是因为协议搞得太复杂了,所以没人用,市面上的基本都是根据 OAuth 2 来的。所以看到 OAuth 你就认为是 2 就行了。
大家最熟悉的例子就是第三方登录了。假设有个论坛叫做“91 论坛”你没有注册过,也懒得填写邮箱 密码注册,那么这时候可以使用第三方登录,比如 QQ 登录。那么问题来了,当你点击 “用 QQ 登录” 这个按钮的时候,论坛怎么安全地知道你的身份呢?会有下面两个问题:
现在陷入了两难境界,论坛无法信任你自己提供 QQ 号,你也不能信任论坛拿走你的账户密码。如果这时候能让 QQ 作为中间人只提供给论坛部分信息就好了,OAuth 就是用来做这个的。
简单来说,方案如下:
总体来说,就是这么简单,协议的细节也不用过分仔细追究,毕竟你也不会从头实现一套验证流程,而一定会用第三方的 OAuth 库。把协议过一遍,掌握协议的要领,遇到问题了再查文档也不迟。
Anyway, 在浏览器中,具体解决方案大致如下:
一、91 论坛的开发者在 QQ 处申请一个开发者账户,获得一个开发者标识,并提供了一个回调接口:
{
'client_id': 91bbs,
'client_secret': 123456,
'callback': "http://91bbs.com/login_callback"
}
二、你在 91 论坛上点击用 QQ 登录,然后页面跳转到 QQ 域 (qq.com) 下,这样你可以安全的输入 QQ 密码,而不用被 91 论坛知道。用 QQ 登录对应的地址:
https://api.qq.com/v1/auth?
response_type=code&
client_id=91bbs&
callback=http://91bbs.com/login_callback&
scope=read
注意其中标识了论坛在上一步 client_id。在这个页面上可能写着你是否授权 XX 论坛访问你的个人信息等等。
三、登录 QQ 后,点击授权通过,然后 QQ 会把你重定向到 redirect_uri 对应的页面,并附加参数 code=xxx,这个是一个临时的一次性授权码。重定向到的页面:
http://91bbs.com/login_callback&code=xxxxxx
四、访问这个页面,就会把这个 code 传递给 91 论坛,但是 91 论坛有了这个 code 还不能直接向 QQ 询问关于你的具体信息。进行下一步操作。
五、91 论坛使用这个 code 向 QQ 申请一个长期有效的 refresh_token,再使用这个 refresh token 获得一个 access token, 这样就可以获取你的 QQ 号等信息,具体获得什么信息,是在第二步的 scope 页面指定的。
POST https://api.qq.com/v1/token
grant_type=authorization_code&
code=AUTH_CODE_HERE&
redirect_uri=REDIRECT_URI&
client_id=CLIENT_ID&
client_secret=CLIENT_SECRET
grant_type 指定了授权的类型,这里我们使用上一步获得的 authorization code 来获取 access token,所以 grant type 就是 authorization code. QQ 返回给 91 论坛的信息:
{
"access_token":"ACCESS_TOKEN",
"token_type":"bearer",
"expires_in":2592000,
"refresh_token":"REFRESH_TOKEN",
"scope":"read",
}
// 除了 Authorization Code 这个 grant_type 以外,后面还会讲到 password grant_type
因为这个 access token 可以随时用来访问你的信息,所以设定了过期时间,这样即使泄露了攻击的时间窗口也不会很长。当 access token 过期后,还可以使用 refresh token 刷新,获得新的有效的 access token,而不需要用户再次登录。refresh token 可以没有过期时间,或者过期时间远比 access token 长,但是因为使用次数少,所以也是相对比较安全的。
POST https://cloud.digitalocean.com/v1/oauth/token?
grant_type=refresh_token&
client_id=CLIENT_ID&
client_secret=CLIENT_SECRET&
refresh_token=REFRESH_TOKEN
六、91 论坛使用 access token 访问你的信息。access token 通常是放在 Authorization 这个 header 中。比如使用 curl 来表示这个访问:
curl -H 'Authorization: Bearer 1.1Zgwxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=' \
'http://api.qq.com/v1/user/123456'
如果 token 正确无误的话,QQ 服务器会返回相应的信息。
七、论坛根据从 QQ 服务器得到的消息,从而知道你真的是 QQ 为 123456 的用户,然后为你创建账户。以后你需要登录也可以重复上面的流程,就可以证明你的身份了。
在上面的过程中,一共出现了四种角色:
其中资源指的就是用户的 QQ 信息,而授权服务器和资源服务器在复杂的结构中往往是分开的。
假设我们要从头实现 QQ,本来我们有自己第一方(官方)App 的资源访问方式,现在还要搞个 OAuth2 实现第三方访问,岂不是要维护两套系统?聪明的你一定已经想到方案了,干嘛还搞自己的资源控制方式?把自己的 App 也视作第三方应用,直接都走 OAuth2 得了。现在的不少 App 也确实是这么搞得。
当第一方应用使用 OAuth 的时候,可以使用另一种更加简单的 grant_type:password。作为第一方,我们可以直接把用户名和密码提交上去,然后获得 access token 和 refresh token。实际上,这和传统的提交用户名和密码,然后设置一个 Cookie 的登录方式完全是一致的,只不过在这里我们使用了 OAuth 约定的一些参数名称罢了。更重要的是,你可以使用现成的 OAuth 库来实现
© 2016-2022 Yifei Kong. Powered by ynotes
All contents are under the CC-BY-NC-SA license, if not otherwise specified.
Opinions expressed here are solely my own and do not express the views or opinions of my employer.
友情链接: MySQL 教程站