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..48065bbac2 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;
@@ -16,41 +18,67 @@ public static class CookieAuthenticationOptionsExtensions
///
public static CookieAuthenticationOptions IntrospectAccessToken(this CookieAuthenticationOptions options, string oidcAuthenticationScheme = "oidc")
{
- 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)
+ {
+ return;
+ }
+
+ var logger = principalContext.HttpContext.RequestServices.GetRequiredService>();
- if (principalContext.Principal != null && principalContext.Principal.Identity != null && principalContext.Principal.Identity.IsAuthenticated)
+ var accessToken = principalContext.Properties.GetTokenValue("access_token");
+ if (!accessToken.IsNullOrWhiteSpace())
{
- var accessToken = principalContext.Properties.GetTokenValue("access_token");
- if (!accessToken.IsNullOrWhiteSpace())
+ var openIdConnectOptions = await GetOpenIdConnectOptions(principalContext, oidcAuthenticationScheme);
+ 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)
{
- 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.IsActive)
- {
- return;
- }
+ logger.LogError(response.Error);
+ await SignOutAsync(principalContext);
+ return;
}
- principalContext.RejectPrincipal();
- await principalContext.HttpContext.SignOutAsync(principalContext.Scheme.Name);
+ if (!response.IsActive)
+ {
+ logger.LogError("The access_token is not active.");
+ await SignOutAsync(principalContext);
+ return;
+ }
+
+ 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 GetOpenIdConnectOptions(CookieValidatePrincipalContext principalContext, string oidcAuthenticationScheme)
+ {
+ var openIdConnectOptions = principalContext.HttpContext.RequestServices.GetRequiredService>().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)
+ {
+ 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
new file mode 100644
index 0000000000..f873f3762b
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore/Microsoft/Extensions/DependencyInjection/CookieAuthenticationOptionsExtensions.cs
@@ -0,0 +1,100 @@
+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
+{
+ ///
+ /// 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(3);
+ validationInterval ??= TimeSpan.FromMinutes(1);
+ options.Events.OnValidatePrincipal = async principalContext =>
+ {
+ if (principalContext.Principal == null || principalContext.Principal.Identity == null || !principalContext.Principal.Identity.IsAuthenticated)
+ {
+ return;
+ }
+
+ var logger = principalContext.HttpContext.RequestServices.GetRequiredService>();
+
+ 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))
+ {
+ logger.LogInformation("The access_token is expired.");
+ await SignOutAsync(principalContext);
+ return;
+ }
+
+ if (principalContext.Properties.IssuedUtc != null && 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 = await GetOpenIdConnectOptions(principalContext, oidcAuthenticationScheme);
+
+ 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 GetOpenIdConnectOptions(CookieValidatePrincipalContext principalContext, string oidcAuthenticationScheme)
+ {
+ var openIdConnectOptions = principalContext.HttpContext.RequestServices.GetRequiredService>().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)
+ {
+ 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 @@
+
+
diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebModule.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebModule.cs
index 55302dde61..8e8ac6c694 100644
--- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebModule.cs
+++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebModule.cs
@@ -145,6 +145,7 @@ public class MyProjectNameWebModule : AbpModule
.AddCookie("Cookies", options =>
{
options.ExpireTimeSpan = TimeSpan.FromDays(365);
+ options.CheckTokenExpiration();
})
.AddAbpOpenIdConnect("oidc", options =>
{
@@ -232,7 +233,7 @@ public class MyProjectNameWebModule : AbpModule
dataProtectionBuilder.PersistKeysToStackExchangeRedis(redis, "MyProjectName-Protection-Keys");
}
}
-
+
private void ConfigureDistributedLocking(
ServiceConfigurationContext context,
IConfiguration configuration)