2

我試圖在訪問令牌到期時使用刷新令牌。類似的問題的答案爲here。而a sample code to renew token一個動作IdentityServer4客戶端 - 在CookieAuthenticationEvents上刷新訪問令牌

和我結束了在startup.cs

app.UseCookieAuthentication(new CookieAuthenticationOptions 
{ 
    AuthenticationScheme = "Cookies", 
    //ExpireTimeSpan = TimeSpan.FromSeconds(100), 
    AutomaticAuthenticate = true, 
    AutomaticChallenge = true, 
    Events = new CookieAuthenticationEvents() 
    { 
     OnValidatePrincipal = async x => 
     { 
      if (x.Properties?.Items[".Token.expires_at"] == null) return; 

      var logger = loggerFactory.CreateLogger(this.GetType()); 

      var now = DateTimeOffset.UtcNow; 
      var tokenExpireTime = DateTime.Parse(x.Properties.Items[".Token.expires_at"]).ToUniversalTime(); 
      var timeElapsed = now.Subtract(x.Properties.IssuedUtc.Value); 
      var timeRemaining = tokenExpireTime.Subtract(now.DateTime); 

      if (timeElapsed > timeRemaining) 
      { 
       var httpContextAuthentication = x.HttpContext.Authentication;//Donot use the HttpContext.Authentication to retrieve anything, this cause recursive call to this event 
       var oldAccessToken = await httpContextAuthentication.GetTokenAsync("access_token"); 
       var oldRefreshToken = await httpContextAuthentication.GetTokenAsync("refresh_token"); 
       logger.LogInformation($"Refresh token :{oldRefreshToken}, old access token:{oldAccessToken}"); 


       var disco = await DiscoveryClient.GetAsync(AuthorityServer); 
       if (disco.IsError) throw new Exception(disco.Error); 

       var tokenClient = new TokenClient(disco.TokenEndpoint, ApplicationId, "secret"); 
       var tokenResult = await tokenClient.RequestRefreshTokenAsync(oldRefreshToken); 
       logger.LogInformation("Refresh token requested. " + tokenResult.ErrorDescription); 


       if (!tokenResult.IsError) 
       { 

        var oldIdToken = await httpContextAuthentication.GetTokenAsync("id_token"); 
        var newAccessToken = tokenResult.AccessToken; 
        var newRefreshToken = tokenResult.RefreshToken; 

        var tokens = new List<AuthenticationToken> 
        { 
         new AuthenticationToken {Name = OpenIdConnectParameterNames.IdToken, Value = oldIdToken}, 
         new AuthenticationToken {Name = OpenIdConnectParameterNames.AccessToken, Value = newAccessToken}, 
         new AuthenticationToken {Name = OpenIdConnectParameterNames.RefreshToken, Value = newRefreshToken} 
        }; 

        var expiresAt = DateTime.UtcNow + TimeSpan.FromSeconds(tokenResult.ExpiresIn); 
        tokens.Add(new AuthenticationToken { Name = "expires_at", Value = expiresAt.ToString("o", CultureInfo.InvariantCulture) }); 

        var info = await httpContextAuthentication.GetAuthenticateInfoAsync("Cookies"); 
        info.Properties.StoreTokens(tokens); 
        await httpContextAuthentication.SignInAsync("Cookies", info.Principal, info.Properties); 

       } 
       x.ShouldRenew = true; 
      } 
      else 
      { 
       logger.LogInformation("Not expired"); 
      } 
     } 

    } 
}); 

客戶端安裝的是下面的代碼如下

AllowAccessTokensViaBrowser = true, 
RefreshTokenUsage = TokenUsage.ReUse, 
RefreshTokenExpiration = TokenExpiration.Sliding, 
AbsoluteRefreshTokenLifetime = 86400,  
AccessTokenLifetime = 10, 
AllowOfflineAccess = true, 
AccessTokenType = AccessTokenType.Reference 

成功登錄後,我得到一個401每隔一個請求。和日誌說

[Identity Server的] 2017年7月4日10:15:58.819 +01:00 [調試] 「TjpIkvHQi ../ cfivu6Nql5ADJJlZRuoJV1QI =」 在數據庫中找到:真

[ [服務器] 2017-07-04 10:15:58.820 +01:00 [調試] 「reference_token」授予值: 「.9e64c1235c6675fcef617914911846fecd72f7b372」在商店中發現,但已經過期 。

[Identity Server] 2017-07-04 10:15:58.821 +01:00 [錯誤]無效的 引用令牌。 「{\」 ValidateLifetime \ 「:真的,
\」 AccessTokenType \ 「:\」 參考\ 「\ 」TokenHandle \「: \」 .. 9e64c1235c6675fcef617914911846fecd72f7b372 \ 「}」

[標識服務器] 2017- 07-04 10:15:58.822 +01:00 [調試]令牌爲 無效。

[Identity Server] 2017-07-04 10:15:58.822 +01:00 [調試]爲不活動令牌創建自檢響應。

[Identity Server] 2017-07-04 10:15:58.822 +01:00 [信息]成功 令牌自省。令牌狀態: 「禁用」,API名稱: 「API1」

任何幫助將通過高度讚賞

UPDATE

基本上,當令牌過期我就得到一個System.StackOverflowException以下行

var tokenExpireTime = DateTime.Parse(x.Properties.Items[".Token.expires_at"]).ToUniversalTime(); 

UPDATE 2不要使用HttpContext.Authentication來檢索任何東西。檢查我的答案下面找到工作實現

回答

2

我在這工作了最後兩天,無法使這項工作。有趣地,在這裏張貼的問題後,2小時內我做它的工作:)

Events = new CookieAuthenticationEvents() 
{ 
    OnValidatePrincipal = async x => 
    { 
     if (x.Properties?.Items[".Token.expires_at"] == null) return; 
     var now = DateTimeOffset.UtcNow; 

     var tokenExpireTime = DateTime.Parse(x.Properties.Items[".Token.expires_at"]).ToUniversalTime(); 
     var timeElapsed = now.Subtract(x.Properties.IssuedUtc.Value); 
     var timeRemaining = tokenExpireTime.Subtract(now.DateTime); 
     WriteMessage($"{timeRemaining} and elapsed at {timeElapsed}"); 
     if (timeElapsed > timeRemaining) 
     { 
      var oldAccessToken = x.Properties.Items[".Token.access_token"]; 

      var oldRefreshToken = x.Properties.Items[".Token.refresh_token"]; 
      WriteMessage($"Refresh token :{oldRefreshToken}, old access token {oldAccessToken}"); 

      var disco = await DiscoveryClient.GetAsync(AuthorityServer); 
      if (disco.IsError) throw new Exception(disco.Error); 

      var tokenClient = new TokenClient(disco.TokenEndpoint, ApplicationId, "secret"); 
      var tokenResult = await tokenClient.RequestRefreshTokenAsync(oldRefreshToken); 

      if (!tokenResult.IsError) 
      { 
       var oldIdToken = x.Properties.Items[".Token.id_token"];//tokenResult.IdentityToken 

       var newAccessToken = tokenResult.AccessToken; 
       var newRefreshToken = tokenResult.RefreshToken; 

       var tokens = new List<AuthenticationToken> 
       { 
        new AuthenticationToken {Name = OpenIdConnectParameterNames.IdToken, Value = oldIdToken}, 
        new AuthenticationToken {Name = OpenIdConnectParameterNames.AccessToken, Value = newAccessToken}, 
        new AuthenticationToken {Name = OpenIdConnectParameterNames.RefreshToken, Value = newRefreshToken} 
       }; 

       var expiresAt = DateTime.UtcNow + TimeSpan.FromSeconds(tokenResult.ExpiresIn); 
       tokens.Add(new AuthenticationToken { Name = "expires_at", Value = expiresAt.ToString("o", CultureInfo.InvariantCulture) }); 

       x.Properties.StoreTokens(tokens); 

       WriteMessage($"oldAccessToken: {oldAccessToken}{Environment.NewLine} and new access token {newAccessToken}"); 

      } 
      x.ShouldRenew = true; 
     } 
    } 
} 

基本上httpContextAuthentication.GetTokenAsync使這個遞歸,因爲這個原因StackOverflowException發生。

請讓我知道,如果這實現了

+0

爲什麼創造AuthenticationTokens的列表時使用oldIdToken代替tokenResult.IdentityToken價值的任何問題? –

+0

@JonasAxelsson是的,'tokenResult.IdentityToken'也可以用來刷新IdentityToken,但在這裏我試圖弄清楚如何刷新令牌在IdS4上工作 – MJK

+1

似乎oldIdToken值不同於tokenResult.IdentityToken,所以它很可能最好使用新的tokenResult.AccessToken和tokenResult.RefreshToken –

相關問題