diff --git a/framework/src/Volo.Abp.AspNetCore.Authentication.OpenIdConnect/Volo.Abp.AspNetCore.Authentication.OpenIdConnect.csproj b/framework/src/Volo.Abp.AspNetCore.Authentication.OpenIdConnect/Volo.Abp.AspNetCore.Authentication.OpenIdConnect.csproj index 4ee09824cf..9f1051fbd5 100644 --- a/framework/src/Volo.Abp.AspNetCore.Authentication.OpenIdConnect/Volo.Abp.AspNetCore.Authentication.OpenIdConnect.csproj +++ b/framework/src/Volo.Abp.AspNetCore.Authentication.OpenIdConnect/Volo.Abp.AspNetCore.Authentication.OpenIdConnect.csproj @@ -8,10 +8,6 @@ - - - - diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Server/Microsoft/AspNetCore/Authentication/Cookies/CookieAuthenticationOptionsExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Components.Server/Microsoft/AspNetCore/Authentication/Cookies/CookieAuthenticationOptionsExtensions.cs index 61c064b376..327088d3e0 100644 --- a/framework/src/Volo.Abp.AspNetCore.Components.Server/Microsoft/AspNetCore/Authentication/Cookies/CookieAuthenticationOptionsExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Components.Server/Microsoft/AspNetCore/Authentication/Cookies/CookieAuthenticationOptionsExtensions.cs @@ -1,7 +1,9 @@ using System; +using System.Threading.Tasks; using IdentityModel.Client; using Microsoft.AspNetCore.Authentication.OpenIdConnect; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; namespace Microsoft.AspNetCore.Authentication.Cookies; @@ -23,6 +25,8 @@ public static class CookieAuthenticationOptionsExtensions if (principalContext.Principal != null && principalContext.Principal.Identity != null && principalContext.Principal.Identity.IsAuthenticated) { + var logger = principalContext.HttpContext.RequestServices.GetRequiredService>(); + var accessToken = principalContext.Properties.GetTokenValue("access_token"); if (!accessToken.IsNullOrWhiteSpace()) { @@ -40,17 +44,36 @@ public static class CookieAuthenticationOptionsExtensions Token = accessToken }); - if (response.IsActive) + if (response.IsError) { + logger.LogError(response.Error); + await SignOutAsync(principalContext); + return; + } + + if (!response.IsActive) + { + logger.LogError("The access_token is not active."); + await SignOutAsync(principalContext); return; } - } - principalContext.RejectPrincipal(); - await principalContext.HttpContext.SignOutAsync(principalContext.Scheme.Name); + logger.LogInformation("The access_token is active."); + } + 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); + } } }; return options; } + + private async static Task SignOutAsync(CookieValidatePrincipalContext principalContext) + { + principalContext.RejectPrincipal(); + await principalContext.HttpContext.SignOutAsync(principalContext.Scheme.Name); + } } diff --git a/framework/src/Volo.Abp.AspNetCore/Microsoft/Extensions/DependencyInjection/CookieAuthenticationOptionsExtensions.cs b/framework/src/Volo.Abp.AspNetCore/Microsoft/Extensions/DependencyInjection/CookieAuthenticationOptionsExtensions.cs index 430eddbcb4..835455795d 100644 --- a/framework/src/Volo.Abp.AspNetCore/Microsoft/Extensions/DependencyInjection/CookieAuthenticationOptionsExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore/Microsoft/Extensions/DependencyInjection/CookieAuthenticationOptionsExtensions.cs @@ -1,31 +1,96 @@ using System; using System.Globalization; +using System.Threading.Tasks; +using IdentityModel.Client; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Cookies; +using Microsoft.AspNetCore.Authentication.OpenIdConnect; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; namespace Microsoft.Extensions.DependencyInjection; public static class CookieAuthenticationOptionsExtensions { - public static CookieAuthenticationOptions CheckTokenExpiration(this CookieAuthenticationOptions options, TimeSpan? advance = null) + /// + /// Check the access_token is expired or inactive. + /// + public static CookieAuthenticationOptions CheckTokenExpiration(this CookieAuthenticationOptions options, string oidcAuthenticationScheme = "oidc", TimeSpan? advance = null, TimeSpan? validationInterval = null) { - advance ??= TimeSpan.FromMinutes(5); + advance ??= TimeSpan.FromMinutes(3); + validationInterval ??= TimeSpan.FromMinutes(1); var originalHandler = options.Events.OnValidatePrincipal; options.Events.OnValidatePrincipal = async principalContext => { originalHandler?.Invoke(principalContext); + if (principalContext.Principal != null && principalContext.Principal.Identity != null && principalContext.Principal.Identity.IsAuthenticated) { + var logger = principalContext.HttpContext.RequestServices.GetRequiredService>(); + var tokenExpiresAt = principalContext.Properties.Items[".Token.expires_at"]; - if (tokenExpiresAt != null && - DateTimeOffset.TryParseExact(tokenExpiresAt, "o", null, DateTimeStyles.RoundtripKind, out var expiresAt) && - expiresAt < DateTimeOffset.UtcNow.Subtract(advance.Value)) + if (DateTimeOffset.TryParseExact(tokenExpiresAt, "o", null, DateTimeStyles.RoundtripKind, out var expiresAt) && expiresAt < DateTimeOffset.UtcNow.Subtract(advance.Value)) { - principalContext.RejectPrincipal(); - await principalContext.HttpContext.SignOutAsync(principalContext.Scheme.Name); + logger.LogInformation("The access_token is expired."); + await SignOutAsync(principalContext); + return; + } + + if (principalContext.Properties.IssuedUtc != null) + { + if (DateTimeOffset.UtcNow.Subtract(principalContext.Properties.IssuedUtc.Value) > validationInterval) + { + logger.LogInformation($"Check the access_token is active every {validationInterval.Value.TotalSeconds} seconds."); + var accessToken = principalContext.Properties.GetTokenValue("access_token"); + if (!accessToken.IsNullOrWhiteSpace()) + { + var openIdConnectOptions = principalContext.HttpContext.RequestServices.GetRequiredService>().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) + { + logger.LogError(response.Error); + await SignOutAsync(principalContext); + return; + } + + if (!response.IsActive) + { + logger.LogError("The access_token is not active."); + await SignOutAsync(principalContext); + return; + } + + 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); + } + } } } }; + return options; } + + private async static Task SignOutAsync(CookieValidatePrincipalContext principalContext) + { + principalContext.RejectPrincipal(); + await principalContext.HttpContext.SignOutAsync(principalContext.Scheme.Name); + } } diff --git a/framework/src/Volo.Abp.AspNetCore/Volo.Abp.AspNetCore.csproj b/framework/src/Volo.Abp.AspNetCore/Volo.Abp.AspNetCore.csproj index aa1090e204..0fe01e9f2b 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo.Abp.AspNetCore.csproj +++ b/framework/src/Volo.Abp.AspNetCore/Volo.Abp.AspNetCore.csproj @@ -26,6 +26,8 @@ + +