OAuth
OAuth是一个解决用户无需向第三方应用提供用户名密码,让第三方应用访问用户私密资源的授权方案。
举例: 用户a,在网站B存有私密信息(年龄、邮箱、头像),而a在访问第三方网站C时,为了让C可以知道a在B网站上的信息,可以通过OAuth授权,让C访问B拿到a的信息。
逻辑步骤
a是下图里的User,B是下图里的Consumer,C是Service Provider
- B网站支持OAuth协议;
- C网站在B网站注册,拿到appId和appSecret,并事先编辑验证回调地址;
- a访问C,并点击获取B网站信息的操作;
- C网站生成带一个未授权RequestToken的链接并跳转到网站B,要求用户进行授权;
- 用户登录后点击授权,完成对RequestToken的授权;
- C网站拿着授权后的RequestToken问B拿AccessToken;
- 通过AccessToken + 资源接口 访问用户的私密资源;
作者:郭无心
链接:https://www.zhihu.com/question/19851243/answer/75070070
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
此图已联系作者
+----------+ +----------+
| |--(A)- Obtaining a Request Token --------->| |
| | | |
| |<-(B)- Request Token ----------------------| |
| | (Unauthorized) | |
| | | |
| | +--------+ | |
| |>-(C)-| -+-(C)- Directing ---------->| |
| | | -+-(D)- User authenticates ->| |
| | | | +----------+ | Service |
| Consumer | | User- | | | | Provider |
| | | Agent -+-(D)->| User | | |
| | | | | | | |
| | | | +----------+ | |
| |<-(E)-| -+-(E)- Request Token ------<| |
| | +--------+ (Authorized) | |
| | | |
| |--(F)- Obtaining a Access Token ---------->| |
| | | |
| |<-(G)- Access Token -----------------------| |
+----------+ +----------+
版本信息
OAuth目前有三个版本
- OAuth1.0 解决用户资源授权问题,以前的OpenId只解决了who的问题,没办法对资源进行区分隔离
- OAuth1.0a 为了解决OAuth1.0存在的安全漏洞,做了个升级补丁
- OAuth2.0 由于OAuth1.0的签名认证逻辑过于复杂、对多终端不友好,所以做了2.0的协议,不兼容OAuth1.0。OAuth2.0 支持多种授权方式(方便不同终端对接)。
服务端对接
以Nodejs为例
使用社区方案passport,passport定义了一套权限认证接口。主流的第三方OAuth登录有对应的passport接口实现,如:facebook、twitter、google等。github搜索 passport ${platform}
就能找到响应的实现。
具体步骤:
- 到对应平台的开发者中心,申请 appId, appSecret,并配置callback回调地址(上图中E步在Consumer的地址);
- 服务端(Nodejs): 根据passport strategy对应文档,配置appId、appSecret;
- 网页端: 加上访问对应strategy的链接增加授权入口;
- 移动端: 根据平台提示,下载对应移动端SDK;
注意,找到的strategy有的是走 OAuth1.0a 有的是走 OAuth2.0 的,比如twitter是OAuth1.0a,如果后端需要拿AccessToken则要自己实现(OAuth2.0回调时直接返回AccessToken),使用的时候需要看清楚。
移动端鉴权方案
上面介绍完OAuth token完成第三方鉴权,并获取资源。
我们自己的服务对于移动端鉴权也可以完成OAuth支持,比如Nodejs可以用oauth2orize。
使用OAuth支持移动端存在的问题
颁发出去的accessToken需要存储并控制过期,redis会比较合适。
其他方案?—— 自己实现cookie session机制
而如果已经使用了redis,则实现类似cookie-session的机制逻辑上更简单,而且接口鉴权跟web端基本保持一致。
请求时带着token,在后端通过加盐hash等手段生成sessionId,恢复session并进行鉴权,这样可以做到前端和app端统一登录,并且走同一套session存储。
这么做的工作量是重写session模块,在浏览器端解析token并完成session设置。同时redis依然是系统依赖。
有更简洁的方法吗? —— jwt
当然有,对于鉴权我们的需求是两个: 鉴权、恢复信息。
jwt可以同时完成,token鉴权、payload存储信息的功能。
操作步骤如下:
- 用户通过鉴权接口 (用户名密码登录/第三方登录后的AccessToken鉴权),服务端返回生成的 jwt,jwt中包含了用户的非敏感信息(session);
- 移动端拿到jwt后,存储在本地,并按照约定的时间通过AccessToken等方式到后端刷新 jwt;(具体过期时间和过期策略可以服务端跟客户端商量)
- 新的请求带着jwt时,服务端只要解析jwt,并取出payload做为session供后面的业务逻辑使用就行了;
缺点:
- 请求协议如果不是ssl,则jwt的payload是暴露在网路中的,所以里面不能存储敏感信息;
- jwt相对一般的token体量大,网络开销受payload体积影响,因此session不宜太大;
实现cookie session机制用redis存储的方式可以作为升级方案。
有更好的方案欢迎讨论
reply to start a discussion