这篇博客本人不知道该怎么定义,因为我是看了一些博客和视频想总结一下,其中cheat的成分肯定不在少数,所以我觉得在一开始都贴出来好了,这样不懂了随时还可以回去看一看困扰自己的问题是不是前人早就踩过坑了。顺便总结一下,好好学习每一天。最终会声明转载自阮一峰老师的博客。后续可能会在使用时再做实战总结以及通读RFC6749的工作
- B站UP主魔王不造反的视频:彻底理解OAuth2协议
- 阮一峰博客:理解OAuth2协议
- 阮一峰博客:OAuth2的一个简单解释 我觉得系统看完一次OAuth2协议之后再来读一次这个文章应该更好
- 阮一峰博客:OAuth 2.0 的四种方式
- 阮一峰博客:GitHub OAuth 第三方登录示例教程
- 关于 OAuth2.0 安全性你应该要知道的一些事
假设你居住在北京海淀区中心的一个小区,最近比较忙没有时间自己做饭,经常需要定外卖。但是小区设有门禁卡,外卖员每次进入的时候都要经历门禁这一关,非常麻烦。所以你希望能有一种方法能让外卖员自己通过门禁进入小区。
你可能想把自己的门禁卡给外卖员,这显然不合适,因为你不知道第二天你要定哪一家,而且突然不想让这个外卖员进入小区了也是非常麻烦的。
于是你向小区门禁的程序员建议开发一个授权系统,当外卖员要进入小区时,只需要点击门口的请求授权按钮,你的手机上就会弹出这个外卖员的信息(姓名、电话、店名),如果你点击授权,外卖员就会获得一个有效期七天的令牌(token),接下来外卖员就可以用这个令牌通过所有被授权的小区的门禁。
这个流程大概就是计算机网络中的OAuth2的大概流程。
这里介绍几个可能在后面用到的名词:
OAuth:Open standard for Authorization
OAuth是一个关于授权的开放网络的标准,它的作用就是“客户端”安全可控地获取“用户”的授权,与“服务提供商”进行互动。它可以授权一个第三方的网站或者APP去访问他们在特定网站上的信息,而无需向第三方的网站或者应用提供账号密码。
简单说,OAuth是一种授权机制。数据的所有者告诉系统,同意授权第三方应用进入系统,获取这些数据。系统从而产生一个短期的进入令牌(token),用来代替密码,供第三方应用使用。
https://ruby-china.org/account/sign_in
常规的登录方法是 输入账号和密码,而这个网站也为我们提供了一个使用Github平台登录的方法。
GitHub
这个按钮这个是我拷贝下来的链接
https://github.com/login/oauth/authorize?client_id=f252166dc176d078abac&redirect_uri=https%3A%2F%2Fruby-china.org%2Faccount%2Fauth%2Fgithub%2Fcallback&response_type=code&state=193643c5105270c202a459fc95c29aa69415a6d8f8b7987f
然后我们看到了一个授权的按钮,一旦授权成功,ruby-China就可以访问本人GitHub账户上的一系列信息,头像、邮箱还有昵称信息。
而传统的模式如果填写了用户名和密码,ruby-China就获得了我的用户名和密码,这一切都基于这个站点是我信任的,如果是一个小众的站点,他可能会保存我的输入,甚至用我的账户去做一些非法的事情。而且信息会被泄露。这也是开发OAuth的原因。
点击授权后,Ruby-China就得到了用户在GitHub上存储的允许访问的账户信息。
我们知道任何的身份鉴别本质上都是基于对请求方的不信任所产生的。 用户可能并不信任这个站点,但是用户信任GitHub。身份鉴别就是为了解决身份的可信任问题。
Ruby-China需要去GitHub去申请一个第三方应用,去申请特定的标识符。
###分析流程
流程如下:
其中最重要的一点就是第二步:用户给客户端授权。
OAuth需要用户授权客户端,那么客户端需要持有什么信息呢?
第三方应用申请token之前,都必须先到授权服务器备案,说明自己的身份。然后就会得到两个身份标识码:Client ID 和Client Secret。这是为了防止token被滥用。没有备案过的第三方应用无法得到token。
接下来是客户端的授权模式
客户必须得到用户的授权(Authorization Grant),才能获得令牌(Access Token)。基于不同的互联网应用场景,OAuth2中定义了四种授权方式。
授权码模式指的是第三方应用先申请一个授权码,再使用该授权码获取token。
这种模式功能最完整,也是流程最严密的。主要是通过客户端(Ruby-China)和授权服务器(GitHub)进行交互,多用于Web应用。授权码通过前端传送,token则存储在后端,而且所有与资源服务器的通信都在后端完成,可以避免token泄露。
客户端通过User-Agent来访问,也就是通过浏览器 来访问。
点击之后,它跳转到了:
这个页面,它的地址我们前面已经做了记录,我们对这个URL做一个处理,为了可以看得清楚一些:
client_id=f252166dc176d078abac
redirect_uri=https%3A%2F%2Fruby-china.org%2Faccount%2Fauth%2Fgithub%2Fcallback
response_type=code
state=193643c5105270c202a459fc95c29aa69415a6d8f8b7987f
我们可以看到client_id(唯一标识Ruby-China)和重定向的URI(点击授权之后会重定向到这个地址),还有response_type与客户端授权模式相关,对于授权码模式来说,就是code。state表示一个本地的状态, 可以理解成是Ruby-China生成的一个随机数,当授权成功之后GitHub会把这个随机数再次发给Ruby-China ,可以确认确实是GitHub发送的,主要是为了防止CSRF攻击;state这个参数是可选的,但是推荐选上。
当点击授权之后,会跳转回到Ruby-China的网页,并提示登录成功!
在这个过程中,Github还会向Ruby-China发送一个请求,请求的地址就是重定向的地址,请求参数包括:code、state,接下来Ruby-China后台可以使用code、client_id和client_secret来获取Access Token。通过token就可以去GitHub的资源服务器申请一些信息。
授权码模式的具体参数:
字段 | 描述 |
---|---|
Response_type | 必填,固定为code,表示这是一个授权码模式请求。 |
Client_id | 必填,在授权服务器注册应用后获得的唯一标识。 |
Redirect_uri | 可选,注册时填写的重定向URI。 |
Scope | 可选,请求资源范围,由逗号隔开,表示token代表的权限是什么。 |
State | 推荐,如果存在,需要原样返回给客户端。 |
因为token可能会过期,所以由提出了一个refresh_token,用于更新token,获取下一次访问需要的token。在授权成功会会返回一个json信息:
{
"access_token":"ACCESS_TOKEN", // token信息
"token_type":"bearer", // token类型,一般为bearer或mac,bearer需要依赖https的安全性且短期有效,需要refresh_token来刷新
"expires_in":2592000, // 过期时间
"refresh_token":"REFRESH_TOKEN", // 刷新token 用于获取下一次token
"scope":"read", // 权限范围,这里为read-only
"uid":100101,
"info":{...}
}
同意授权后,授权服务器直接把token放到重定向URI中返回回来了。不传code而是直接传token,这里token对用户是可见的,而且客户端也不需要被授权服务器认证,不推荐这种 方式。
这种模式下,用户向客户端提供自己的账号和密码(GitHub上的),客户端使用这些信息向服务提供商来获取token。用户必须对客户端绝对信任才行。
客户端以自己的名义向授权服务器请求一个认证,直接通过客户端的密钥和id获取token,无需用户参与。比较适合为消费者设计。不支持refresh_token。
令牌token和口令password的作用都是为了让用户安全进入系统,差异如下:
使用token登录时,系统一般也不会做二次确认,所以token和password一样都需要保密好,泄露的后果是一样的。