IdentityServer4實戰 - AccessToken 生命周期分析


一.前言

IdentityServer4實戰這個系列主要介紹一些在IdentityServer4(后文稱:ids4),在實際使用過程中容易出現的問題,以及使用技巧,不定期更新,謝謝大家關注。使用過ids4的朋友應該知道,可以通過設置AccessTokenLifetime屬性,來控制AccessToken的存活時間,但是細心的朋友可能會發現,Token到期了依然能通過授權,這是怎么回事呢,下面我帶大家一起來揭開神秘面紗。

二.關於 ID Token 和 AccessToken

Openid Connect(后文稱:OIDC)是在OAuth2.0協議上進行了擴展,OIDC=Identity+OAuth2.0,使其擁有身份認證+授權的能。它在OAuth2上構建了一個身份層,是一個基於OAuth2協議的身份認證標准協議。我們都知道OAuth2是一個授權協議,它無法提供完善的身份認證功能,OIDC使用OAuth2的授權服務器來為第三方客戶端提供用戶的身份認證,並把對應的身份認證信息傳遞給客戶端,且可以適用於各種類型的客戶端(比如服務端應用,移動APP,JS應用),且完全兼容OAuth2,也就是說你搭建了一個OIDC的服務后,也可以當作一個OAuth2的服務來用。應用場景如圖:

OAuth2提供了Access Token來解決授權第三方客戶端訪問受保護資源的問題;OIDC在這個基礎上提供了ID Token來解決第三方客戶端標識用戶身份認證的問題。OIDC的核心在於在OAuth2的授權流程中,一並提供用戶的身份認證信息(ID Token)給到第三方客戶端,ID Token使用JWT格式來包裝,得益於JWT(JSON Web Token)的自包含性,緊湊性以及防篡改機制,使得ID Token可以安全的傳遞給第三方客戶端程序並且容易被驗證。此外還提供了UserInfo的接口,用戶獲取用戶的更完整的信息。

簡而言之ID Token就是JWT格式的數據,包含一個人類用戶的身份認證的信息,一個ID Token的例子如下:

{
     "iss": "https://server.example.com",
     "sub": "24400320",
     "aud": "s6BhdRkqt3",
    "nonce": "n-0S6_WzA2Mj",
     "exp": 1311281970,
    "iat": 1311280970,
     "auth_time": 1311280969,
     "acr": "urn:mace:incommon:iap:silver"
 }

看到上面的數據是不是感覺很熟悉,這是一個我們從ids4申請的"AccessToken":

eyJhbGciOiJSUzI1NiIsImtpZCI6IjhlM2U2MWY1ZWUyZDgwMGNlYjE2NmE5NGRjODczMTY0IiwidHlwIjoiSldUIn0.eyJuYmYiOjE1MjU1Nzg3MTUsImV4cCI6MTUyNTU3ODcxNiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1MDAwIiwiYXVkIjpbImh0dHA6Ly9sb2NhbGhvc3Q6NTAwMC9yZXNvdXJjZXMiLCJhcGkxIl0sImNsaWVudF9pZCI6InJvLmNsaWVudCIsInN1YiI6IjEiLCJhdXRoX3RpbWUiOjE1MjU1Nzg3MTUsImlkcCI6ImxvY2FsIiwic2NvcGUiOlsiYXBpMSJdLCJhbXIiOlsicHdkIl19.JXU4bXUqf8QD4zQz61XC2WTKURtNIVhH23zQPJzOmEtYbQvO2oRP58sCfDQxADeImZ7O0vH4YXIfL8j60B-sAYJev7c2hnjVhHTJ0t-0bUPlLs43cqNG6RarZ8FyfHyhrvIwYBpJXKNROfr6GfLb4Vdpw4ZEd4AC2k2tHuKMfyrrTzqS0oUs1RwqH7KZ1W7pXDr_V2L4PjgCqOQelXAB_V5YXzR9E52FIXnKNzCVnWHmhiTSWg-ptONOoHss1a-ElWejXskTlMBQitnxSno05s4O6vp5R8zqMuo3j57SnPZVaTuR4AUVpDdVmFF9x9k-fHuXyqarsW6YGsXgTTA2Lw

我們將上面的Token解碼可以看見:

我想不用我多說,就可以看見我們的ID Token在哪里吧。

三.設置AccessToken過期時間

我們在ids端設置我們的客戶端資源的時候有一個AccessTokenLifetime屬性,此屬性可以設置我們申請的Token的有效時間,單位是秒,默認3600秒也就是一個小時。

代碼示例:

new Client
{
    ClientId = "ro.client",
    AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
    AccessTokenLifetime = 5,
    ClientSecrets = 
    {
        new Secret("secret".Sha256())
    },
    AllowedScopes = { "api1" }
}

本文所用代碼,為ids4文檔中,第二個QuickStart,文末會給出地址。

Client對象還包含一個 IdentityTokenLifetime屬性,是用來設置ID Token的存活時間,但是,我們獲得AccessToken以后,訪問API資源等,是用的授權,此屬性無法影響AccessToken的有效期,這也是我在上面解釋了ID Token和AccessToken的區別的原因,希望大家不要搞混淆了。

我們上面將AccessToken的存活時間設置為5s,我們修改客戶端的代碼改一下,讓他暫停6s再次去訪問APi資源,看看會發生什么:

我們先看看返回的AccessToken信息里,過期時間已經變成了5s:

看看暫停之后的結果:

可以看到,本來Token應該過期無法訪問的,但是還是成功訪問API獲取到了信息:

這是怎么回事呢,和我們想的有點不一樣,請聽下節分解!

四.時間偏移(ClockSkew )

有這樣的場景,如果你的AccessToken還有5s過期,這時你通過這個AccessToken去訪問API資源,但是這時網絡堵塞,可能請求10s才到達目標,那這時怎么辦?如果需要保持所持有的AccessToken一直有效,是否需要提前刷新或者再次申請AccessToken?如果你本地的時間和API資源服務的時間具有時間差異可能是幾秒,幾十秒等等,那么你該如何判斷你所持有的AccessToken的有效性?

上述的這些問題,都是我們將時間理想化了,所以當我們的API資源受到請求根據AccessToken進行驗證的時候,會有一個時間偏移,通俗的講就是將AccessToken的邏輯過期時間往后推遲了,這個時間默認是5分鍾。比如我們的AccessToken應該在2018年5月6日16:50:55過期,那么實際上在API資源進行驗證的時候,容忍在過期時間后的五分鍾以內,此AccessToken依然是有效的,即在API資源驗證時,此AccessToken的真正過期時間為2018年5月6日16:55:55,這個時間差就是用來解決上述問題的。這也是為什么上面我們將AccessToken設置5s過期,但實際上5s之后還能用它成功訪問API。

此設置是針對於JWT的,這里需要注意。

五.設置時間偏移

1.獲取默認過期時間

默認過期時間我們可以通過JwtBearerOptions對象的TokenValidationParameters屬性的ClockSkew屬性來獲取。

可以看見默認的時間偏移為5分鍾,那么如何來自定義這個值呢。

2.設置時間偏移

我們可以通過IdentityServerAuthenticationOptions對象提供JwtValidationClockSkew屬性來自定義時間偏移,這個設置是在API資源的,因為當我們請求API資源的時候,是API資源自行進行驗證的。

代碼如下:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvcCore()
        .AddAuthorization()
        .AddJsonFormatters();
    services.AddAuthentication("Bearer")
        .AddIdentityServerAuthentication(options =>
        {
            options.Authority = "http://localhost:5000";
            options.RequireHttpsMetadata = false;
            options.JwtValidationClockSkew = TimeSpan.FromSeconds(0);
            options.ApiName = "api1";
        });
}

我們通過options.JwtValidationClockSkew = TimeSpan.FromSeconds(0);將這個時間偏移設置為了0s,那么我們現在再運行我們前面的程序,設置AccessToken過期時間為5s,我們暫停6s,會發生什么。

可以看到提示“Unauthorized”,可以看到現在的情況和我們前面所想的情況一致了。這就是時間偏移的作用。

六.寫在最后

在實際生產環境中,一定要盡量保持各個服務,各個節點的時間同步,使用標准時間。然后這個時間偏移如沒有特殊需求不建議去更改它,這個就是這樣設計的,官方也是不推薦去更改它。如果設置過短可能引起文章說的問題哦。歡迎大家加入QQ群(4656606)和我一起交流,寫本文也是群里許多朋友問過這個問題,以前一直沒注意,今天才算解開了它的秘密。

本文所用代碼下載:

https://github.com/stulzq/IdentityServer4.Samples/tree/master/Practice/02_AccessTokenLifetime

參考資料:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM