我試圖在訪問令牌到期時使用刷新令牌。類似的問題的答案爲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來檢索任何東西。檢查我的答案下面找到工作實現
爲什麼創造AuthenticationTokens的列表時使用oldIdToken代替tokenResult.IdentityToken價值的任何問題? –
@JonasAxelsson是的,'tokenResult.IdentityToken'也可以用來刷新IdentityToken,但在這裏我試圖弄清楚如何刷新令牌在IdS4上工作 – MJK
似乎oldIdToken值不同於tokenResult.IdentityToken,所以它很可能最好使用新的tokenResult.AccessToken和tokenResult.RefreshToken –