记录最近作的一个 demo,前端使用 React
,用 React Router
实现前端路由,Koa 2
搭建 API Server, 最后经过 Nginx
作请求转发。前端
第一篇:React + Node 单页应用「一」前端搭建
React + Node 单页应用「二」OAuth 2.0 受权认证 & GitHub 受权实践node
这是第二篇,介绍下 OAuth 2.0
受权机制,以及 Github App 受权过程,经过获取受权使用 Github API。react
传统的 CS(Client-Server) 受权模式下,请求访问受保护资源(用户信息)时,客户端须要向服务器提供资源所属用户的证书,为了让第三方拿到资源,用户就得将证书共享给第三方应用。这种方式会致使如下几个问题:ios
为了解决这个问题,OAuth 协议引入了受权层,并将客户端与服务端的角色区分开,在 OAuth 协议中,客户端请求的 Access_token
,被托管在资源服务器,但受用户控制,而且与用户凭证彻底不一样。git
举个例子,如今有一家档案馆,档案馆中有不少资料,这些资料有些涉及到机密,有些只是常规资料,
研究员小李须要进入档案馆查找常规资料,因而就跑去找罗馆长批条子github
“馆长馆长,我要看一些常规资料,请给我批个条子吧”json
罗馆长了解了小李要看的是常规资料,很爽快地批了axios
“没问题,给,这是赞成的条子”跨域
因而小李拿到条子后,径直去找了档案馆门卫大壮
“大壮,你看这是馆长给我批的查看常规资料的条子”,
大壮确认没问题后
“嗯,既然馆长赞成了,来,这是常规文件的钥匙”,
因而小李就拿着钥匙进入馆内开始找资料,馆内每道房门都有一把锁,若是房间里存放的是常规资料,小李只须要出示钥匙就能够进入,但存放涉密资料的房间,小李的钥匙打不开,必须找馆长批一份查看涉密资料的条子,再拿着条子去大壮那儿换一把新的钥匙。
资源全部者
能够受权获取受保护资源的实体,若是这个全部者是人,即常规意义的用户,即档案馆的馆长。
资源服务器
资源服务器用于存储资源,接收请求,并将资源返回给携带合法 Access_token
的请求,在咱们的例子中,档案馆就充当着资源服务器的角色。
客户端
获取受权后,表明用户请求资源的第三方应用,也就是故事中的研究员小李。
受权服务器
受权服务器在成功认证资源拥有者并获取到受权后,发放 Access_token
给客户端,故事中大壮的主要工做内容就是发放访问钥匙。
/** * 协议流程 * 引自 RFC6749 */ +--------+ +---------------+ | |--(A)- Authorization Request ->| Resource | | | | Owner | | |<-(B)-- Authorization Grant ---| | | | +---------------+ | | | | +---------------+ | |--(C)-- Authorization Grant -->| Authorization | | Client | | Server | | |<-(D)----- Access Token -------| | | | +---------------+ | | | | +---------------+ | |--(E)----- Access Token ------>| Resource | | | | Server | | |<-(F)--- Protected Resource ---| | +--------+ +---------------+
上面这张图是引自 RFC6749 的 OAuth 2.0 受权流程,归纳以下
Access_token
Access_token
,第三方应用就能够访问资源服务器中的资源了Github 有一套很是完备的 API,在没有得到受权时,仅有部分功能可用,例如获取用户信息、仓库信息等,而且调用次数被限制在了一小时仅容许60次
受权后,每小时调用次数放开到每小时 5000 次,而且申请受权时,能够选择申请的权限范围,例如申请 star 项目、follow 用户的权限(咱们此次用到的)等等,咱们经过申请完整的权限,甚至能够写一个 Github 第三方应用。
要获取受权,首先须要在 Github 注册一个应用,注册这个应用以前,须要准备好两个东西
github.lijundong.com
(若是是 IP 记得加协议头)github.lijundong.com/github/getauth
可依照如下路径建立一个受权 APP,
Github > setting > Developer settings > OAuth Apps > New OAuth App
进入注册界面,须要填写应用名、应用主页地址、应用简介、以及回调 URL,建立完成会跳转到 APP 管理页面,在管理页面能够更新应用信息以及上传应用 Logo,而且你将看到你的应用的 Client ID
、Client Secret
,接下来获取权限须要用到这两个东西。
GitHub 官方的受权流程:
第一步:页面跳转到 GitHub 的受权页
在项目中,我选择了用 <a>
标签连接的方式跳转。
GET https://github.com/login/oauth/authorize?client_id=xxx&scope=xxx /** * client_id:注册应用的 client_id 必填 * scope:申请的权限范围 选填,默认用户权限为空 */
第二步:回调接口收到 GitHub 的回调请求,得到 code
咱们在注册应用时,设置了受权回调 URL,上一步中,Github 受权页成功得到用户受权后,会带上 code 请求咱们设置的回调 URL,在这一步中,咱们的 Server 就拿到了用户的受权 code。
第三步:经过 code 获取 Access_token
最后一步经过已有 code,加上应用的 client_id
和 client_secret
,咱们向 Github 申请 Access_token
。
/** * code:第二步获取到的 code 必填 * client_secret:注册应用 client_secret 必填 * client_id:注册应用的 client_id 必填 */ const rp = require('request-promise') let option = { uri: 'https://github.com/login/oauth/access_token?client_id=' + clientId + '&client_secret=' + clientSecret + '&code=' + code, json: true } let tokenResp = await rp(option);
第四步:将得到的 Access_token
写入页面的 cookie 中。
ctx.cookies.set('access_token', tokenResp.access_token, { 'httpOnly': false })
由于第三方应用请求 GitHub API 涉及到跨域,第一篇文章已经提到了Github API 只支持 XHR 跨域请求,一些同窗若是用 Fetch 跨域请求 API 会致使请求 request type
变成 option
,因此项目中改用 axios
进行网络请求。
这里以获取登录用户基本信息为例,
import Axios from 'axios' import Cookie from 'js-cookie' const access_token = Cookie.get('access_token'); getLoginInfo() { let that = this; let url = API.GITHUB.GET_LOGIN_INFO; Axios.get(url, { params: { access_token: access_token } }).then(function(res) { that.setState({ loginInfo: res.data, }); }).catch(function (error) { console.error(error); }) }
参考: