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 0dd2c33cb84..2aead07ce77 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,86 +1,16 @@
using System;
-using System.Threading.Tasks;
-using Duende.IdentityModel.Client;
-using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Logging;
-using Microsoft.Extensions.Options;
-using Volo.Abp.Threading;
namespace Microsoft.AspNetCore.Authentication.Cookies;
public static class CookieAuthenticationOptionsExtensions
{
///
- /// Introspect access token on validating the principal.
+ /// Check the access_token is expired or inactive.
///
- ///
- ///
- ///
+ [Obsolete("Use CheckTokenExpiration method instead.")]
public static CookieAuthenticationOptions IntrospectAccessToken(this CookieAuthenticationOptions options, string oidcAuthenticationScheme = "oidc")
{
- 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 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.");
- }
- 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)
- {
- var cancellationTokenProvider = principalContext.HttpContext.RequestServices.GetRequiredService();
- openIdConnectOptions.Configuration = await openIdConnectOptions.ConfigurationManager.GetConfigurationAsync(cancellationTokenProvider.Token);
- }
-
- return openIdConnectOptions;
- }
-
- private async static Task SignOutAsync(CookieValidatePrincipalContext principalContext)
- {
- principalContext.RejectPrincipal();
- await principalContext.HttpContext.SignOutAsync(principalContext.Scheme.Name);
+ return options.CheckTokenExpiration(oidcAuthenticationScheme, null, TimeSpan.FromMinutes(1));
}
}
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 c37e75ef324..7d6955f08bb 100644
--- a/framework/src/Volo.Abp.AspNetCore/Microsoft/Extensions/DependencyInjection/CookieAuthenticationOptionsExtensions.cs
+++ b/framework/src/Volo.Abp.AspNetCore/Microsoft/Extensions/DependencyInjection/CookieAuthenticationOptionsExtensions.cs
@@ -14,41 +14,56 @@ namespace Microsoft.Extensions.DependencyInjection;
public static class CookieAuthenticationOptionsExtensions
{
///
- /// Check the access_token is expired or inactive.
+ /// Check if 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);
+ var previousHandler = options.Events.OnValidatePrincipal;
options.Events.OnValidatePrincipal = async principalContext =>
{
if (principalContext.Principal == null || principalContext.Principal.Identity == null || !principalContext.Principal.Identity.IsAuthenticated)
{
+ await InvokePreviousHandlerAsync(principalContext, previousHandler);
return;
}
var logger = principalContext.HttpContext.RequestServices.GetRequiredService>();
var tokenExpiresAt = principalContext.Properties.GetString(".Token.expires_at");
- if (!tokenExpiresAt.IsNullOrWhiteSpace() && DateTimeOffset.TryParseExact(tokenExpiresAt, "o", null, DateTimeStyles.RoundtripKind, out var expiresAt) &&
- expiresAt < DateTimeOffset.UtcNow.Subtract(advance.Value))
+ if (!tokenExpiresAt.IsNullOrWhiteSpace() && DateTimeOffset.TryParseExact(tokenExpiresAt, "o", CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out var expiresAt) &&
+ expiresAt <= DateTimeOffset.UtcNow.Add(advance.Value))
{
- logger.LogInformation("The access_token is expired.");
- await SignOutAsync(principalContext);
+ logger.LogInformation("The access_token expires within {AdvanceSeconds}s; signing out.", advance.Value.TotalSeconds);
+ await SignOutAndInvokePreviousHandlerAsync(principalContext, previousHandler);
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.");
+ logger.LogInformation("Checking access_token activity every {Seconds} seconds.", validationInterval.Value.TotalSeconds);
var accessToken = principalContext.Properties.GetTokenValue("access_token");
if (!accessToken.IsNullOrWhiteSpace())
{
var openIdConnectOptions = await GetOpenIdConnectOptions(principalContext, oidcAuthenticationScheme);
+ var introspectionEndpoint = openIdConnectOptions.Configuration?.IntrospectionEndpoint;
+ if (introspectionEndpoint.IsNullOrWhiteSpace() && !openIdConnectOptions.Authority.IsNullOrWhiteSpace())
+ {
+ introspectionEndpoint = openIdConnectOptions.Authority.EnsureEndsWith('/') + "connect/introspect";
+ }
+
+ if (introspectionEndpoint.IsNullOrWhiteSpace())
+ {
+ logger.LogWarning("No introspection endpoint configured. Skipping token activity check.");
+ await InvokePreviousHandlerAsync(principalContext, previousHandler);
+ return;
+ }
+
var response = await openIdConnectOptions.Backchannel.IntrospectTokenAsync(new TokenIntrospectionRequest
{
- Address = openIdConnectOptions.Configuration?.IntrospectionEndpoint ?? openIdConnectOptions.Authority!.EnsureEndsWith('/') + "connect/introspect",
+ Address = introspectionEndpoint,
ClientId = openIdConnectOptions.ClientId!,
ClientSecret = openIdConnectOptions.ClientSecret,
Token = accessToken
@@ -56,15 +71,15 @@ public static CookieAuthenticationOptions CheckTokenExpiration(this CookieAuthen
if (response.IsError)
{
- logger.LogError(response.Error);
- await SignOutAsync(principalContext);
+ logger.LogError("Token introspection error: {Error}", response.Error);
+ await SignOutAndInvokePreviousHandlerAsync(principalContext, previousHandler);
return;
}
if (!response.IsActive)
{
logger.LogError("The access_token is not active.");
- await SignOutAsync(principalContext);
+ await SignOutAndInvokePreviousHandlerAsync(principalContext, previousHandler);
return;
}
@@ -73,16 +88,18 @@ public static CookieAuthenticationOptions CheckTokenExpiration(this CookieAuthen
}
else
{
- logger.LogError("The access_token is not found in the cookie properties, Please make sure SaveTokens of OpenIdConnectOptions is set as true.");
+ logger.LogError("The access_token is not found in the cookie properties. Ensure SaveTokens of OpenIdConnectOptions is true.");
await SignOutAsync(principalContext);
}
}
+
+ await InvokePreviousHandlerAsync(principalContext, previousHandler);
};
return options;
}
- private async static Task GetOpenIdConnectOptions(CookieValidatePrincipalContext principalContext, string oidcAuthenticationScheme)
+ private static async Task GetOpenIdConnectOptions(CookieValidatePrincipalContext principalContext, string oidcAuthenticationScheme)
{
var openIdConnectOptions = principalContext.HttpContext.RequestServices.GetRequiredService>().Get(oidcAuthenticationScheme);
var cancellationTokenProvider = principalContext.HttpContext.RequestServices.GetRequiredService();
@@ -94,9 +111,20 @@ private async static Task GetOpenIdConnectOptions(CookieVa
return openIdConnectOptions;
}
- private async static Task SignOutAsync(CookieValidatePrincipalContext principalContext)
+ private static async Task SignOutAsync(CookieValidatePrincipalContext principalContext)
{
principalContext.RejectPrincipal();
await principalContext.HttpContext.SignOutAsync(principalContext.Scheme.Name);
}
+
+ private static Task InvokePreviousHandlerAsync(CookieValidatePrincipalContext principalContext, Func? previousHandler)
+ {
+ return previousHandler != null ? previousHandler(principalContext) : Task.CompletedTask;
+ }
+
+ private static async Task SignOutAndInvokePreviousHandlerAsync(CookieValidatePrincipalContext principalContext, Func? previousHandler)
+ {
+ await SignOutAsync(principalContext);
+ await InvokePreviousHandlerAsync(principalContext, previousHandler);
+ }
}