OAuth 2.0 是一個行業的標準授權協議。它的最終目的是爲第三方應用頒發一個有時效性的令牌 token。使得第三方應用能夠通過該令牌獲取相關的資源。常見的場景就是:第三方登錄。

借用LinkedIn上的OAuth2.0的流程圖,登錄流程大致如下:

Github 集成

Github的集成相對簡單,而且限制較少。詳細的文檔在:

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

第一步: 創建 OAuth應用

首先到登錄github,到 Settings -> Developer settings -> OAuth Apps 創建一個新的 OAuth應用,如下圖:

這裏會生成 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 參數,之後你就可以在後臺獲取用戶信息。

以下代碼基於 OnceIO 實現,與 expressjs 用法非常類似,主要增加了模塊支持。

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' }

然後可以用這些信息自動註冊或登錄用戶。

PS: OnceDoc.request 對象是 OnceOA 自己實現的一個輕量極 http cleint,與 request 模塊用法類似,但不像 request 那麼臃腫,代碼在安裝包的 oncedoc/svr/request.js 中。

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

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'
    }
}

/*
Exports
*/
typeof module !== 'undefined' && (module.exports = {
    ...
  , SOCIAL_SIGN         : SOCIAL_SIGN
});
  1. 將 social-sign 複製到 oncedoc/mod 目錄下
  2. 在 /onceos -> 應用管理中啓用 social-sign
  3. 重啓 onceoa
相關文章