在這篇文章中,我們将探索由 OAuth2 定義的Refresh Token的概念。我們将會明白為什麼他們會這樣做,以及他們如何與其他類型的Token進行比較。我們也将通過一個簡單的例子來學習如何使用它們。 更新: access token access token id token
目前這篇文章寫的Auth0還沒有通過 OpenID Connect認證 。本文中使用的某些術語(如
)不符合此規範,但符合 OAuth2規範 。OpenID Connect在
(用于通路授權伺服器的API)和
(用于針對資源伺服器的用戶端驗證)之間建立明确的差別。
介紹
現代的認證或者授權的解決方案已經将
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 token
和
refresh token
- Access Token攜帶了直接通路資源的必要資訊。換句話說,當用戶端将
傳給管理資源的伺服器時,該伺服器可以使用access token
中包含的資訊來決定是否授權給用戶端。token
通常有一個過期時間,而且通常時間非常短暫。access token
- Refresh Token攜帶了用來擷取新的access token的必要資訊。換句話說,當用戶端需要使用access token來通路特定資源的時候,用戶端可以使用refresh token來向認證伺服器請求下發新的access token。通常情況下,當舊的access token失效之後,才需要獲得新的access token,或者是在第一次通路資源的時候。refresh token也有過期時間但是時間相對較長。refresh token對存儲的要求通常會非常嚴格,以確定它不會被洩漏。它們也可以被授權伺服器列入黑名單。
通常由具體的實作來定義token是透明的還是不透明的。通用實作允許對access token進行直接授權檢查。也就是說,當access token傳遞給管理資源的伺服器時,伺服器可以讀取token中包含的資訊,并決定使用者是否被授權(不需要對授權伺服器進行檢查)。這就是token必須簽名的原因之一(例如使用JWS)。另一方面,refresh token通常需要對授權伺服器進行檢查。處理授權檢查的這種分離方式有以下3個優點:
- 改進了對授權伺服器的通路模式(更低的負載,更快的檢查)
- 洩露access token的通路視窗更短(這些access token會很快過期,進而減少洩露的token通路受保護資源的機會)
- 滑動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指令。此示例中的代碼基于
中的示例。我們已經修改了基本示例,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/原文釋出時間為:2018年01月15日
原文作者:
我是鐘鐘本文來源:
開源中國如需轉載請聯系原作者