使用node.js和oAuth2协议集成Github/LinkedIn第三方登录以OnceOA模块源码为例


发布者 清竹-Kris  发布时间 1579175459634
关键字 JavaScript  Node.JS  OnceOA 

OAuth 2.0 是一个行业的标准授权协议。它的最终目的是为第三方应用颁发一个有时效性的令牌 token。使得第三方应用能够通过该令牌获取相关的资源。常见的场景就是:第三方登录。

登录流程大致如下:

image

Github 集成

Github的集成相对简单,而且限制较少。详细的文档在:

https://developer.github.com/apps/building-oauth-apps/authorizing-oauth-apps/

第一步: 创建 OAuth应用

首先到登录github,到 Settings -> Developer settings -> OAuth Apps 创建一个新的 OAuth应用,如下图:

github_social_sign.png

这里会生成 client_id, client_secret 两个参数,需要记下来,写到配置文件中。
这里还需要手动填写 redirect_uri 回调网址,即用户从您的网站跳到 Github.com 并登录返回的网址。

第二步:生成 github 登录网址

在您的网站上使用 client_id 和 redirect_uri ,生成第三方登录网址,如:

https://github.com/login/oauth/authorize?client_id=f283ce279713c1c9ac3c&redirect_uri=http://localhost:8064/social-sign/oauth/github/callback

用户点击这个地址,进入github登录。

第三步:github 重定向到网站

用户登录github后,github会重定向到你之前设置的 redirect_uri,并增加一个 code 参数,之后你就可以在后台获取用户信息。

1. Github登录后转向 redirect_uri

// 第一步:github回调,传递 code,用来交换 access_token
app.get('/social-sign/oauth/github/callback', function(req, res) {
  var code  = req.query.code
  if (!code) {
    res.send('no code')
    return
  }
  ...
}

2. 用code交换access_token

// 第二步:获取 access_token
OnceDoc.request({
  url: 'https://github.com/login/oauth/access_token'
, headers: {
      Accept: "application/json"
  }
, data: {
      client_id     : SOCIAL_SIGN.github.client_id
    , client_secret : SOCIAL_SIGN.github.client_secret
    , code          : code
  }
, type: 'qs'
}, function(err, response, data) {
..

3. 用access_token获取用户信息

// 第三步:获取用户信息,注册必须包含,User-Agent 建议是github用户名或者APP名
OnceDoc.request({
    url: 'https://api.github.com/user'
  , headers: {
      'User-Agent'    : 'OnceDB',
      'Authorization' : 'token ' + access_token
    }
}, function(err, response, data) {
...

调用成功后,返回的用户JSON数据示例:

{ login: 'newghost',
id: 88888888888888888,
node_id: 'SDFSXXXXXXDFSDFSDF',
avatar_url: 'https://avatars0.githubusercontent.com/u/1529044?v=4',
gravatar_id: '',
url: 'https://api.github.com/users/newghost',
html_url: 'https://github.com/newghost',
followers_url: 'https://api.github.com/users/newghost/followers',
following_url:
 'https://api.github.com/users/newghost/following{/other_user}',
gists_url: 'https://api.github.com/users/newghost/gists{/gist_id}',
starred_url:
 'https://api.github.com/users/newghost/starred{/owner}{/repo}',
subscriptions_url: 'https://api.github.com/users/newghost/subscriptions',
organizations_url: 'https://api.github.com/users/newghost/orgs',
repos_url: 'https://api.github.com/users/newghost/repos',
events_url: 'https://api.github.com/users/newghost/events{/privacy}',
received_events_url: 'https://api.github.com/users/newghost/received_events',
type: 'User',
site_admin: false,
name: 'Kris Zhang',
company: null,
blog: '',
location: 'Shanghai',
email: ' SDFSXXXXXXDFSDFSDF',
hireable: null,
bio: null,
public_repos: 20,
public_gists: 0,
followers: 74,
following: 3,
created_at: '2012-03-12T14:10:56Z',
updated_at: '2019-11-20T07:41:56Z' }

然后可以用这些信息自动注册或登录用户。

LinkedIn 集成

LinkedIn 最近对 OAuth 的请求接口进行了更新,限制了一些敏感信息的访问。截止目前,这篇文章使用还是旧的接口。

具体可参照这篇官方文章: https://developer.linkedin.com/zh-cn/docs/oauth2#

410 接口错误

不过进行到最后获取用户信息时,你可能会发现LinkedIn会返回410错误。

<error>
  <status>410</status>
  <timestamp>1579159582344</timestamp>
  <request-id>27XR33REUM</request-id>
  <error-code>0</error-code>
  <message>This resource is no longer available under v1 APIs</message>
</error>

接口更新

LinkedIn 的接口已经更新到 v2 版本,需要对之前的那篇官方文档进行一些修改:

将文中

access_token_url = 'https://api.linkedin.com/uas/oauth2/accessToken'
authorize_url = 'https://www.linkedin.com/uas/oauth2/authorization'

替换成

access_token_url = 'https://www.linkedin.com/oauth/v2/accessToken'
authorize_url = 'https://www.linkedin.com/oauth/v2/authorization'

将用户信息获取地址: https://api.linkedin.com/v1/people/~
替换成: https://api.linkedin.com/v2/me

用户信息示例

登录成功后,请求 https://api.linkedin.com/v2/me 会获取如下数据:

{ localizedLastName: 'Zhang',
  lastName:
   { localized: { en_US: 'Zhang' },
     preferredLocale: { country: 'US', language: 'en' } },
  firstName:
   { localized: { en_US: 'Kris' },
     preferredLocale: { country: 'US', language: 'en' } },
  profilePicture:
   { displayImage: 'urn:li:digitalmediaAsset:C4D03AQGxcGwMAF2UJA' },
  id: 'VbANm-OM_K',
  localizedFirstName: 'Kris' }

LinkedIn 隐藏了头像,邮箱,用户名等隐私信息,而且获取这些并不容易,这里并没有实现。

Social-Sign 模块源码

源码地址: https://github.com/OnceDoc/onceoa-modules/tree/master/social-sign

  1. 该源码是 OnceOA 的一个功能扩展模块。
  2. 该源码采用 OnceIO 编写,与 ExpressJS 非常类似,在中间件等写法上略有不同,并添加了 模块系统 支持。
  3. OnceDoc.request 对象是 OnceOA 自己实现的一个轻量极 http cleint,与 request 模块用法类似,但不像 request 那么臃肿,该文件在 OnceOA 安装包的 /onceai/oncedoc/svr/request.js 中,可独立使用。

social-sign 模块安装方法:

  1. 在 oncedoc/config.js 中添加 SOCIAL_SIGN 配置

var SOCIAL_SIGN = {
    github: {
        client_id     : 'zzzzzzzzzzzzzzzzzzzzz1'
      , client_secret : 'xxxxxxxxxxxxxxxxxxxxxx1'
      , redirect_uri  : 'http://127.0.0.1:8064/social-sign/oauth/github/callback'
    },
    linkedin: {
        client_id     : 'xxxxxxxxxxxxxxxxxxxx2'
      , client_secret : 'yyyyyyyyyyyyyyyyyyyy2'
      , redirect_uri  : 'http://127.0.0.1:8064/social-sign/oauth/linkedin/callback'
    }
}

/*
导出引用
*/
typeof module !== 'undefined' && (module.exports = {
    ...
  , SOCIAL_SIGN         : SOCIAL_SIGN
});

  1. 将 social-sign 复制到 oncedoc/mod 目录下
  2. 进入 OnceOA 桌面, /onceos -> 应用管理中启用 social-sign
  3. 重启 OnceOA 进程








 热门文章 - 分享最多
  1. Redis源码分析,在C语言中将当前时间转化成毫秒微秒整数值
  2. JavaScript在Array数组中按指定位置删除或添加元素对象
  3. Node.JS发送http请求批量检查文件中的网页地址、服务是否有效可用
  4. Linux下的tar压缩解压缩命令详解,创建解压目录到.tar.gz包
  5. CentOS注册系统服务,添加自动启动脚本
  6. 用OnceOA旺司在树莓派等arm设备免费搭建私有云版有道云笔记文档管理系统,在线编辑Markdown,同步备份手机照片
  7. node.js含有%百分号时,发送get请求时浏览器地址自动编码的问题
  8. Node.JS用纯JavaScript生成图片或滑块式验证码
  9. 树莓派ARM开发板使用TF卡启动和系统安装到EMMC启动,硬盘存储读写速度对比测试
  10. Node.JS枚举统计当前文件夹和子目录下所有代码文件行数

 相关阅读
  1. 让pre和textarea等HTML元素去掉滚动条自动换行自适应文本内容高度
  2. Facebook发布全新JavaScript引擎Hermes:越来越像Java字节码,JS要统一全端?
  3. 在嵌入式设备树莓派上编译QuickJS教程:一个C语言编写的极简JavaScript引擎
  4. 使用JavaScript的Proxy监听对象属性变化并进行类public/private的访问控制
  5. JavaScript求一个字符串的字节长度
  6. JavaScript中将字符串true或false转换成Boolean类型
  7. jQuery用$.prop,$.attr方法来获取或设置checkbox当前选中状态
  8. Node.JS中用concat和push连接两个或多个数组的性能比较
  9. 判断是否为对象typeof abc == 'object' 与 instanceof 性能比较
  10. typeof判断参数是否为undefined与全等判断法性能比较

  开源的 OurJS
OurJS开源博客已经迁移到 OnceOA 平台。

  关注我们
扫一扫即可关注我们:
OnceJS

OnceOA