如何使用 OAuth 接入第三方用戶信息

「LeanCloud Web 應用開發實踐」系列直播及文章分享持續進行中。
每週二週四晚上 8 點開始,時長預計 45 分鐘。在 「leanCloud通信」 微信公衆號回覆 「公開課」 便可獲取直播連接。javascript

點擊查看完整公開課視頻css

OAuth 簡介 01:34

OAuth(開放受權)是一個開放標準,容許用戶讓第三方應用訪問該用戶在某一網站上存儲的私密的資源(如照片,視頻,聯繫人列表),而無需將用戶名和密碼提供給第三方應用。維基百科html

提示:須要用戶在別的網站上的私密信息時,直接向用戶要帳號密碼有點太不專業了。

以 Ticket 爲例,轉換下說法就是:java

容許用戶讓 Ticket 應用訪問該用戶在 LeanCloud 上存儲的私密資源(如帳號,應用列表),而無需將用戶名和密碼提供給 Ticket。git

使用 Ticket 爲例,介紹 OAuth 受權過程 04:20

預備工做

  1. Ticket 向 LeanCloud 申請 OAuth 接入。
  2. LeanCloud 審覈經過後,給 Ticket 頒發 clientIdclientSecret

用戶申請受權 06:15

1.用戶訪問 Ticket 應用,當 Ticket 須要用戶在 LeanCloud 上的信息時(好比 Ticket 想使用用戶在 LeanCloud 上的信息來註冊本身的網站),OAuth 受權過程開始。github

2.Ticket 服務端拼接 LeanCloud 的受權地址給用戶,並附帶一些信息,包括:express

  • clientId:準備工做裏面 LeanCloud 辦法給 Ticket 的 clientId。
  • scope:Ticket 但願獲取用戶在 LeanCloud 上信息的範圍,好比只要基本帳戶信息,或者再加上應用列表信息等。

    注意:不是要的信息越多越好,用戶可能由於應用須要的信息過多而放棄受權。

  • callbackUrl:當用戶確認受權以後,將會跳轉回來的頁面。

3.用戶瀏覽器根據剛纔的響應,跳轉到 LeanCloud 的受權頁面。LeanCloud 受權頁面會展示一些信息:api

  • LeanCloud 當前登陸用戶(若是沒有登陸會要求登陸)。
  • 哪一個系統須要獲取 LeanCloud 上的權限,由於受權頁的請求地址有 clientId
  • 獲取什麼權限,由於受權頁的請求地址有 scope

用戶根據這些信息判斷是否贊成受權:若是取消,OAuth 受權流程終止;若是贊成,LeanCloud 會生成一個重定向請求到 Ticket,並在請求上附帶一個屬性 code。該 code 在 LeanCloud 內部會記錄,而且和 Ticket 應用,還有當前受權用戶關聯。至於調轉到 Ticket 的哪一個地址,由剛纔 Ticket 重定向過來時候的 callbackUrl 決定。瀏覽器

  1. 用戶瀏覽器根據重定向請求繼續訪問 Ticket 的相關頁面,並攜帶了 code 信息。Ticket 服務端會向 LeanCloud 發起請求,獲取用戶的 accessToken 信息,請求會攜帶一些參數:
  • clientId:準備工做裏面 LeanCloud 辦法給 Ticket 的 clientIdbash

  • clientSecret:準備工做裏面 LeanCloud 辦法給 Ticket 的 clientSecret

  • code:確認受權後,LeanCloud 返回給用戶,再經過用戶瀏覽器頁面重定向跳轉提交到 Ticket。

LeanCloud 根據參數信息就能肯定是哪一個應用要獲取哪一個用戶的 accessToken,若是全部信息確認無誤,則返回 accessToken

提示:clientSecret 是私密的,不能泄漏,建議不要直接配置在項目代碼中。若是部署在雲引擎,建議使用雲引擎的環境變量來保存這些數據。雲引擎環境變量設置方式: LeanCloud 控制檯 -> 雲引擎 -> 設置 -> 自定義環境變量,增長鬚要的變量名和變量值,點保存,下次部署時生效。

  1. 當 Ticket 服務端拿到用戶的 accessToken 以後,就能夠經過該信息做爲憑證去請求這用戶的信息(固然須要在 scope 的範圍內)。

至此,OAuth 受權結束。

相關代碼介紹 25:26
本期視頻使用的代碼地址:github.com/leancloud/t…

版本:664259e

可使用下面的命令獲取:

git clone https://github.com/leancloud/ticket.git
cd ticket
git checkout 664259e複製代碼

整個流程涉及到的代碼部分:

  1. 用戶登陸頁關於 OAuth 受權的代碼 modules/Login.js
<div className={css.wrap}>
  <h1 className='font-logo'>歡迎回來</h1>
  <hr />
  <p>目前只支持經過 {ORG_NAME} OAuth 受權進行登陸</p>
    <a href='/oauth/login' className='btn btn-primary'>前往 {ORG_NAME} 受權頁</a>
</div>複製代碼

可見,當用戶點擊「前往 LeanCloud 受權頁」按鈕是,將請求 GET /oauth/login 路由。

  1. 服務端的路由定義在 api/index.js
...
router.use('/oauth/login', require('./oauth').login(loginCallbackUrl))
...複製代碼

路由方法定義在 api/oauth.js 的 login 方法中

exports.login = (callbackUrl) => {
  return (req, res) => {
    const loginUrl = serverDomain + '/1.1/authorize?' +
      qs.stringify({
        client_id: config.oauthKey,
        response_type: 'code',
        redirect_uri: callbackUrl,
        scope: oauthScope,
      })
    res.redirect(loginUrl)
  }
}複製代碼

該方法接受一個 callbackUrl 參數,返回一個 express 的路由方法(即接收 requestresponse 爲參數的方法)。在這個路由方法中拼接了 LeanCloud 受權頁的請求,而後向客戶端回覆一個 302 響應(由 res.redirect() 方法實現)。

  1. 用戶瀏覽器跳轉到 LeanCloud 受權頁,受權成功後,用戶瀏覽器重定向到 Ticket 的 相關路由定義
...
router.use(loginCallbackPath, require('./oauth').loginCallback(loginCallbackUrl))
...複製代碼

路由的 具體實現

exports.loginCallback = (callbackUrl) => {
  return (req, res) => {
    getAccessToken(req.query.code, callbackUrl).then((accessToken) => {
      accessToken.uid = '' + accessToken.uid
      return AV.User.signUpOrlogInWithAuthData(accessToken, 'leancloud')
    }).then((user) => {
      if (_.isEqual(user.createdAt, user.updatedAt)) {
        // 第一次登陸,從 LeanCloud 初始化用戶信息
        return initUserInfo(user)
      }
      return user
    }).then((user) => {
      res.redirect('/login?token=' + user._sessionToken)
    })
  }
}複製代碼

可見路由的實現中:

  1. 先使用請求攜帶的 code 信息到 LeanCloud 網站獲取該用戶的 accessToken(詳見 getAccessToken)。
  2. 使用 JS SDK 的 AV.User.signUpOrlogInWithAuthData() 的方法來註冊或者登錄用戶(根據是否有相同受權信息的用戶決定)。這樣註冊的用戶,帳號和密碼都是隨機生成,_User 表的 authData 列會保存用戶在對應平臺的受權信息。
  3. 若是用戶是第一次登錄,則使用該用戶在 LeanCloud 上的 usernameemail 信息來設置用戶在 Ticket 裏的信息(詳見 initUserInfo1)。
  4. 生成 302 響應,並將用戶的 sessionToken 做爲 queryString,進行客戶端登陸(res.redirect('/login?token=' + user._sessionToken))。
  • 客戶端收到服務端響應後,使用 sessionToken 進行客戶端登陸,代碼 modules/Login.js
const query = nextProps.location.query
if (query.token) {
  return AV.User.become(query.token)
  ...
}複製代碼

至此,OAuth 受權,以及服務端建立(或登陸)用戶,以及客戶端同步登陸過程所有結束。

若是須要用戶在 LeanCloud 上的其餘信息,Ticket 服務端可使用用戶的 accessToken_User表的authData 屬性中)來獲取,能夠參考這些方法:

  • getClientInfo:獲取用戶基本信息
  • getApps:獲取用戶在 LeanCloud 上的應用列表。
  • getApp:獲取用戶在 LeanCloud 上某個應用的詳情。
  • getAccount:獲取用戶在 LeanCloud 上帳戶的詳情,主要用來判斷是否有權限提交工單。

其餘說明 45:08

咱們只介紹了 OAuth 的最基本流程,以及最必要的請求參數,至於 OAuth 受權爲什麼須要這些步驟,以及每一步的某些參數爲什麼要這樣設計,建議你們參考更詳細的文檔或協議說明。

若是本身的應用要申請別的網站 OAuth 受權(好比 QQ),能夠查看對應網站提供的 OAuth 相關文檔。

若是要本身實現 OAuth Server,不須要本身實現,各個語言都有相關的庫,能極大的下降實現成本。

相關文章
相關標籤/搜索