|
|
@ -19,68 +19,61 @@ public static class CookieAuthenticationOptionsExtensions |
|
|
{ |
|
|
{ |
|
|
advance ??= TimeSpan.FromMinutes(3); |
|
|
advance ??= TimeSpan.FromMinutes(3); |
|
|
validationInterval ??= TimeSpan.FromMinutes(1); |
|
|
validationInterval ??= TimeSpan.FromMinutes(1); |
|
|
var originalHandler = options.Events.OnValidatePrincipal; |
|
|
|
|
|
options.Events.OnValidatePrincipal = async principalContext => |
|
|
options.Events.OnValidatePrincipal = async principalContext => |
|
|
{ |
|
|
{ |
|
|
originalHandler?.Invoke(principalContext); |
|
|
if (principalContext.Principal == null || principalContext.Principal.Identity == null || !principalContext.Principal.Identity.IsAuthenticated) |
|
|
|
|
|
{ |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
var logger = principalContext.HttpContext.RequestServices.GetRequiredService<ILogger<CookieAuthenticationOptions>>(); |
|
|
|
|
|
|
|
|
if (principalContext.Principal != null && principalContext.Principal.Identity != null && principalContext.Principal.Identity.IsAuthenticated) |
|
|
var tokenExpiresAt = principalContext.Properties.Items[".Token.expires_at"]; |
|
|
|
|
|
if (DateTimeOffset.TryParseExact(tokenExpiresAt, "o", null, DateTimeStyles.RoundtripKind, out var expiresAt) && |
|
|
|
|
|
expiresAt < DateTimeOffset.UtcNow.Subtract(advance.Value)) |
|
|
{ |
|
|
{ |
|
|
var logger = principalContext.HttpContext.RequestServices.GetRequiredService<ILogger<CookieAuthenticationOptions>>(); |
|
|
logger.LogInformation("The access_token is expired."); |
|
|
|
|
|
await SignOutAsync(principalContext); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
var tokenExpiresAt = principalContext.Properties.Items[".Token.expires_at"]; |
|
|
if (principalContext.Properties.IssuedUtc != null && DateTimeOffset.UtcNow.Subtract(principalContext.Properties.IssuedUtc.Value) > validationInterval) |
|
|
if (DateTimeOffset.TryParseExact(tokenExpiresAt, "o", null, DateTimeStyles.RoundtripKind, out var expiresAt) && expiresAt < DateTimeOffset.UtcNow.Subtract(advance.Value)) |
|
|
{ |
|
|
|
|
|
logger.LogInformation($"Check the access_token is active every {validationInterval.Value.TotalSeconds} seconds."); |
|
|
|
|
|
var accessToken = principalContext.Properties.GetTokenValue("access_token"); |
|
|
|
|
|
if (!accessToken.IsNullOrWhiteSpace()) |
|
|
{ |
|
|
{ |
|
|
logger.LogInformation("The access_token is expired."); |
|
|
var openIdConnectOptions = await GetOpenIdConnectOptions(principalContext, oidcAuthenticationScheme); |
|
|
await SignOutAsync(principalContext); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (principalContext.Properties.IssuedUtc != null) |
|
|
var response = await openIdConnectOptions.Backchannel.IntrospectTokenAsync(new TokenIntrospectionRequest |
|
|
{ |
|
|
|
|
|
if (DateTimeOffset.UtcNow.Subtract(principalContext.Properties.IssuedUtc.Value) > validationInterval) |
|
|
|
|
|
{ |
|
|
{ |
|
|
logger.LogInformation($"Check the access_token is active every {validationInterval.Value.TotalSeconds} seconds."); |
|
|
Address = openIdConnectOptions.Configuration?.IntrospectionEndpoint ?? openIdConnectOptions.Authority.EnsureEndsWith('/') + "connect/introspect", |
|
|
var accessToken = principalContext.Properties.GetTokenValue("access_token"); |
|
|
ClientId = openIdConnectOptions.ClientId, |
|
|
if (!accessToken.IsNullOrWhiteSpace()) |
|
|
ClientSecret = openIdConnectOptions.ClientSecret, |
|
|
{ |
|
|
Token = accessToken |
|
|
var openIdConnectOptions = principalContext.HttpContext.RequestServices.GetRequiredService<IOptionsMonitor<OpenIdConnectOptions>>().Get(oidcAuthenticationScheme); |
|
|
}); |
|
|
if (openIdConnectOptions.Configuration == null && openIdConnectOptions.ConfigurationManager != null) |
|
|
|
|
|
{ |
|
|
|
|
|
openIdConnectOptions.Configuration = await openIdConnectOptions.ConfigurationManager.GetConfigurationAsync(principalContext.HttpContext.RequestAborted); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
var response = await openIdConnectOptions.Backchannel.IntrospectTokenAsync(new TokenIntrospectionRequest |
|
|
|
|
|
{ |
|
|
|
|
|
Address = openIdConnectOptions.Configuration?.IntrospectionEndpoint ?? openIdConnectOptions.Authority.EnsureEndsWith('/') + "connect/introspect", |
|
|
|
|
|
ClientId = openIdConnectOptions.ClientId, |
|
|
|
|
|
ClientSecret = openIdConnectOptions.ClientSecret, |
|
|
|
|
|
Token = accessToken |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
if (response.IsError) |
|
|
if (response.IsError) |
|
|
{ |
|
|
{ |
|
|
logger.LogError(response.Error); |
|
|
logger.LogError(response.Error); |
|
|
await SignOutAsync(principalContext); |
|
|
await SignOutAsync(principalContext); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (!response.IsActive) |
|
|
|
|
|
{ |
|
|
|
|
|
logger.LogError("The access_token is not active."); |
|
|
|
|
|
await SignOutAsync(principalContext); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
logger.LogInformation("The access_token is active."); |
|
|
if (!response.IsActive) |
|
|
principalContext.ShouldRenew = true; |
|
|
{ |
|
|
} |
|
|
logger.LogError("The access_token is not active."); |
|
|
else |
|
|
await SignOutAsync(principalContext); |
|
|
{ |
|
|
return; |
|
|
logger.LogError("The access_token is not found in the cookie properties, Please make sure SaveTokens of OpenIdConnectOptions is set as true."); |
|
|
|
|
|
await SignOutAsync(principalContext); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
logger.LogInformation("The access_token is active."); |
|
|
|
|
|
principalContext.ShouldRenew = true; |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
logger.LogError("The access_token is not found in the cookie properties, Please make sure SaveTokens of OpenIdConnectOptions is set as true."); |
|
|
|
|
|
await SignOutAsync(principalContext); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
}; |
|
|
}; |
|
|
@ -88,6 +81,17 @@ public static class CookieAuthenticationOptionsExtensions |
|
|
return options; |
|
|
return options; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private async static Task<OpenIdConnectOptions> GetOpenIdConnectOptions(CookieValidatePrincipalContext principalContext, string oidcAuthenticationScheme) |
|
|
|
|
|
{ |
|
|
|
|
|
var openIdConnectOptions = principalContext.HttpContext.RequestServices.GetRequiredService<IOptionsMonitor<OpenIdConnectOptions>>().Get(oidcAuthenticationScheme); |
|
|
|
|
|
if (openIdConnectOptions.Configuration == null && openIdConnectOptions.ConfigurationManager != null) |
|
|
|
|
|
{ |
|
|
|
|
|
openIdConnectOptions.Configuration = await openIdConnectOptions.ConfigurationManager.GetConfigurationAsync(principalContext.HttpContext.RequestAborted); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return openIdConnectOptions; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
private async static Task SignOutAsync(CookieValidatePrincipalContext principalContext) |
|
|
private async static Task SignOutAsync(CookieValidatePrincipalContext principalContext) |
|
|
{ |
|
|
{ |
|
|
principalContext.RejectPrincipal(); |
|
|
principalContext.RejectPrincipal(); |
|
|
|