Refresh Token的使用場景以及如何與JWT互動

zhongzhong05發表於2018-01-11

在這篇文章中,我們將探索由OAuth2定義的Refresh Token的概念。我們將會明白為什麼他們會這樣做,以及他們如何與其他型別的Token進行比較。我們也將通過一個簡單的例子來學習如何使用它們。

更新: 目前這篇文章寫的Auth0還沒有通過OpenID Connect認證。本文中使用的某些術語(如access token)不符合此規範,但符合OAuth2規範。OpenID Connect在access token(用於訪問授權伺服器的API)和id token(用於針對資源伺服器的客戶端驗證)之間建立明確的區別。

介紹

現代的認證或者授權的解決方案已經將token引入到了協議當中。token是一種特殊的資料片段,用來授權使用者執行特定的操作,或允許客戶獲得關於授權過程的額外資訊(然後完成)。換句話說,令牌是允許授權過程執行的資訊。該資訊是否可由客戶端(或授權伺服器以外的任何方)讀取或解析,由該實現定義。重要的是:客戶端獲取這些資訊,然後用來獲取特定的資源。JSON Web Token(JWT)規範定義了一種代表通用的token資訊的方式。

JWT簡短回顧

JWT定義了可以表示與認證/授權過程有關的某些共同資訊的方式。顧名思義,資料格式是JSON。JWT擁有subject,issuer,過期時間等通用屬性。JWT與其他規範(如JSON Web簽名(JWS)和JSON Web加密(JWE))結合使用時會變得非常有用。 這些規範不僅提供了授權token通常需要的所有資訊,還提供了一種驗證token內容的方法,以便它不會被篡改(JWS)和一種加密資訊的方法,以使其對於客戶端(JWE)。資料格式(及其他優點)的簡單性已經幫助JWT成為最常見的token型別之一。如果您有興趣學習如何在您的Web應用程式中實現JWT,請檢視Ryan Chenkie撰寫的優秀文章

Token型別

為了這篇文章的目的,我們將重點討論兩種最常見的token型別:access tokenrefresh token

  • Access Token攜帶了直接訪問資源的必要資訊。換句話說,當客戶端將access token傳給管理資源的伺服器時,該伺服器可以使用token中包含的資訊來決定是否授權給客戶端。access token通常有一個過期時間,而且通常時間非常短暫。

Refresh Token的使用場景以及如何與JWT互動

  • Refresh Token攜帶了用來獲取新的access token的必要資訊。換句話說,當客戶端需要使用access token來訪問特定資源的時候,客戶端可以使用refresh token來向認證伺服器請求下發新的access token。通常情況下,當舊的access token失效之後,才需要獲得新的access token,或者是在第一次訪問資源的時候。refresh token也有過期時間但是時間相對較長。refresh token對儲存的要求通常會非常嚴格,以確保它不會被洩漏。它們也可以被授權伺服器列入黑名單。

Refresh Token的使用場景以及如何與JWT互動

通常由具體的實現來定義token是透明的還是不透明的。通用實現允許對access token進行直接授權檢查。也就是說,當access token傳遞給管理資源的伺服器時,伺服器可以讀取token中包含的資訊,並決定使用者是否被授權(不需要對授權伺服器進行檢查)。這就是token必須簽名的原因之一(例如使用JWS)。另一方面,refresh token通常需要對授權伺服器進行檢查。處理授權檢查的這種分離方式有以下3個優點:

  1. 改進了對授權伺服器的訪問模式(更低的負載,更快的檢查)
  2. 洩露access token的訪問視窗更短(這些access token會很快過期,從而減少洩露的token訪問受保護資源的機會)
  3. 滑動session(見下文)

滑動session

滑動session是隻一段時間不活動後過期的session。正如你想到的,使用access token和refresh token可以很容易實現這個功能。當使用者執行操作時,會發出一個新的access token。如果使用者使用過期的access token,則session被認為是不活動的,並且需要新的access token。這個token是否可以通過access token獲得,或者是否需要新的認證輪迴,由開發團隊的要求來定義。

安全考慮

refresh token的存活時間較長。這意味著當客戶端獲取refresh token時,必須安全的儲存此token以防止潛在攻擊者使用此token。如果refresh token洩露,它可能會被用來獲取新的access token(並訪問受保護的資源),直到它被列入黑名單或到期(可能需要很長時間)。refrsh token必須發給單個經過身份驗證的客戶端,以防止其他方使用洩漏的token。訪問令牌必須保密,但是正如你所想象的那樣,安全考慮因其壽命較短而不那麼嚴格。

例項:Refresh Token發放伺服器

為了這個例子的目的,我們使用一個基於node-oauth2-server的簡單的伺服器來發布access token和refresh token。訪問受保護的資源需要access token。客戶端使用簡單的curl命令。此示例中的程式碼基於node-oauth2-server中的示例。我們已經修改了基本示例,access token使用JWT格式。Node-oauth2-server為模型使用預定義的API。你可以點這裡檢視文件。以下程式碼展示瞭如何實現JWT格式的access token模型。

免責宣告:請注意以下示例中的程式碼不是為生產環境準備的。

model.generateToken = function(type, req, callback) {
  //Use the default implementation for refresh tokens
  console.log('generateToken: ' + type);
  if(type === 'refreshToken') {
    callback(null, null);
    return;
  }

  //Use JWT for access tokens
  var token = jwt.sign({
    user: req.user.id
  }, secretKey, {
    expiresIn: model.accessTokenLifetime,
    subject: req.client.clientId
  });

  callback(null, token);
}

model.getAccessToken = function (bearerToken, callback) {
  console.log('in getAccessToken (bearerToken: ' + bearerToken + ')');

  try {
    var decoded = jwt.verify(bearerToken, secretKey, {
        ignoreExpiration: true //handled by OAuth2 server implementation
    });
    callback(null, {
      accessToken: bearerToken,
      clientId: decoded.sub,
      userId: decoded.user,
      expires: new Date(decoded.exp * 1000)
    });
  } catch(e) {    
    callback(e);
  }
};

model.saveAccessToken = function (token, clientId, expires, userId, callback) {
  console.log('in saveAccessToken (token: ' + token +
              ', clientId: ' + clientId + ', userId: ' + userId.id +
              ', expires: ' + expires + ')');

  //No need to store JWT tokens.
  console.log(jwt.decode(token, secretKey));

  callback(null);
};
複製程式碼

OAuth2 token端點(/oauth/token)處理所有型別的授權(密碼和refresh token)的發放。其它所有端點都是受保護的,需要檢查access token。

// Handle token grant requests
app.all('/oauth/token', app.oauth.grant());

app.get('/secret', app.oauth.authorise(), function (req, res) {
  // Will require a valid access_token
  res.send('Secret area');
});
複製程式碼

因此,例如,假設有一個使用者'test',密碼'test'和一個客戶端'testclient',客戶端密碼'secret',可以請求一個新的access token/refresh token對,如下所示:

$ curl -X POST -H 'Authorization: Basic dGVzdGNsaWVudDpzZWNyZXQ=' -d 'grant_type=password&username=test&password=test' localhost:3000/oauth/token

{
    "token_type":"bearer",
    "access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiVlx1MDAxNcKbwoNUwoonbFPCu8KhwrYiLCJpYXQiOjE0NDQyNjI1NDMsImV4cCI6MTQ0NDI2MjU2M30.MldruS1PvZaRZIJR4legQaauQ3_DYKxxP2rFnD37Ip4",
    "expires_in":20,
    "refresh_token":"fdb8fdbecf1d03ce5e6125c067733c0d51de209c"
}
複製程式碼

授權頭包含以BASE64(testclient:secret)編碼的客戶端ID和金鑰。

使用該access token訪問受保護的資源:

$ curl 'localhost:3000/secret?access_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiVlx1MDAxNcKbwoNUwoonbFPCu8KhwrYiLCJpYXQiOjE0NDQyNjI1NDMsImV4cCI6MTQ0NDI2MjU2M30.MldruS1PvZaRZIJR4legQaauQ3_DYKxxP2rFnD37Ip4'

Secret area
複製程式碼

由於JWT,訪問”安全區域“(就是受保護資源)不需要通過查詢資料庫來校驗access token。

一旦token過期:

$ curl 'localhost:3000/secret?access_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiVlx1MDAxNcKbwoNUwoonbFPCu8KhwrYiLCJpYXQiOjE0NDQyNjI2MTEsImV4cCI6MTQ0NDI2MjYzMX0.KkHI8KkF4nmi9z6rAQu9uffJjiJuNnsMg1DC3CnmEV0'

{
    "code":401,
    "error":"invalid_token",
    "error_description":"The access token provided has expired."
}
複製程式碼

現在我們可以通過refresh token來獲取新的access token,如下所示:

$ curl -X POST -H 'Authorization: Basic dGVzdGNsaWVudDpzZWNyZXQ=' -d 'refresh_token=fdb8fdbecf1d03ce5e6125c067733c0d51de209c&grant_type=refresh_token' localhost:3000/oauth/token

{
    "token_type":"bearer",
    "access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiVlx1MDAxNcKbwoNUwoonbFPCu8KhwrYiLCJpYXQiOjE0NDQyNjI4NjYsImV4cCI6MTQ0NDI2Mjg4Nn0.Dww7TC-d0teDAgsmKHw7bhF2THNichsE6rVJq9xu_2s",
    "expires_in":20,
    "refresh_token":"7fd15938c823cf58e78019bea2af142f9449696a"
}
複製程式碼

這裡檢視完整程式碼。

另外:在你的auth0應用中使用refresh token

在auth0應用中我們為你解決了認證的難點。一旦你配置了我們的應用程式,你就可以根據這裡的文件來獲取refresh token。

結論

refresh token提升了安全性,並縮短了授權時間,提供了訪問授權伺服器的更好的一種新模式。使用JWT + JWS等工具可以簡化實現。如果您有興趣瞭解更多關於token(和cookies)的資訊,請檢視我們的文章

原文地址:https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/

相關文章