diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AbpAspNetCoreUnitOfWorkOptions.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AbpAspNetCoreUnitOfWorkOptions.cs
index 34ba5f29c6..891b6cacf1 100644
--- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AbpAspNetCoreUnitOfWorkOptions.cs
+++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AbpAspNetCoreUnitOfWorkOptions.cs
@@ -29,13 +29,10 @@ public class AbpAspNetCoreUnitOfWorkOptions
public bool CompleteUnitOfWorkOnResponseStarting { get; set; } = false;
///
- /// Absolute request path prefixes (matched by segment) that opt-in to
- /// even when it is globally disabled (for example
- /// "/connect" matches "/connect/token" but not "/connections"). Each prefix is matched against both
- /// the request path and the path base + request path, so an endpoint configured with the path base
- /// still matches. A trailing slash is normalized; blank, non-absolute, and root ("/") entries are
- /// ignored - use to enable it for every request
- /// handled by the middleware.
+ /// Request path prefixes that opt-in to even when
+ /// it is globally disabled. A request whose path starts with one of these values (for example
+ /// "/connect") is included, matched like . Use
+ /// to enable it for every request handled by the middleware.
///
public List CompleteUnitOfWorkOnResponseStartingUrls { get; } = new List();
}
diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AbpUnitOfWorkMiddleware.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AbpUnitOfWorkMiddleware.cs
index 211a5be2cf..61ac3cc5fa 100644
--- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AbpUnitOfWorkMiddleware.cs
+++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AbpUnitOfWorkMiddleware.cs
@@ -70,35 +70,9 @@ public class AbpUnitOfWorkMiddleware : AbpMiddlewareBase, ITransientDependency
private bool ShouldCompleteOnResponseStarting(HttpContext context)
{
- if (_options.CompleteUnitOfWorkOnResponseStarting)
- {
- return true;
- }
-
- foreach (var url in _options.CompleteUnitOfWorkOnResponseStartingUrls)
- {
- if (string.IsNullOrWhiteSpace(url))
- {
- continue;
- }
-
- // Normalize a trailing slash ("/connect/" behaves like "/connect") and ignore non-absolute entries.
- var prefix = url.TrimEnd('/');
- if (!prefix.StartsWith("/", StringComparison.Ordinal))
- {
- continue;
- }
-
- // Match both the request path and the path base + path, so an absolute endpoint that includes
- // the path base still matches when the path base is stripped from Request.Path.
- if (context.Request.Path.StartsWithSegments(prefix, StringComparison.OrdinalIgnoreCase) ||
- context.Request.PathBase.Add(context.Request.Path).StartsWithSegments(prefix, StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
- }
-
- return false;
+ return _options.CompleteUnitOfWorkOnResponseStarting ||
+ (context.Request.Path.Value != null &&
+ _options.CompleteUnitOfWorkOnResponseStartingUrls.Any(x => context.Request.Path.Value.StartsWith(x, StringComparison.OrdinalIgnoreCase)));
}
protected async override Task ShouldSkipAsync(HttpContext context, RequestDelegate next)
diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcTestModule.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcTestModule.cs
index 02663eae90..4339104b30 100644
--- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcTestModule.cs
+++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcTestModule.cs
@@ -164,9 +164,6 @@ public class AbpAspNetCoreMvcTestModule : AbpModule
app.UseStaticFiles();
app.UseAbpRequestLocalization();
app.UseAbpSecurityHeaders();
- // Moves the "/pathbase-test" prefix into Request.PathBase so a unit of work opt-in test can
- // exercise path base matching; a no-op for every other request.
- app.UsePathBase("/pathbase-test");
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/UnitOfWorkMiddleware_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/UnitOfWorkMiddleware_Tests.cs
index 26f81ef3a0..283a7ad699 100644
--- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/UnitOfWorkMiddleware_Tests.cs
+++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/UnitOfWorkMiddleware_Tests.cs
@@ -119,34 +119,4 @@ public class UnitOfWorkMiddleware_Tests : AspNetCoreMvcTestBase
var result = await GetResponseAsStringAsync("/api/unitofwork-test/CommitBeforeResponseFlush");
result.ShouldBe("first:completed");
}
-
- [Fact]
- public async Task Opt_In_Url_With_A_Non_Segment_Prefix_Should_Not_Match()
- {
- Options.CompleteUnitOfWorkOnResponseStartingUrls.Add("/api/unitofwork-test/Commit");
-
- var result = await GetResponseAsStringAsync("/api/unitofwork-test/CommitBeforeResponseFlush");
- result.ShouldBe("first:not-completed");
- }
-
- [Fact]
- public async Task Blank_Or_Malformed_Opt_In_Urls_Are_Ignored()
- {
- Options.CompleteUnitOfWorkOnResponseStartingUrls.Add("");
- Options.CompleteUnitOfWorkOnResponseStartingUrls.Add(" ");
- Options.CompleteUnitOfWorkOnResponseStartingUrls.Add("api/no-leading-slash");
-
- var result = await GetResponseAsStringAsync("/api/unitofwork-test/CommitBeforeResponseFlush");
- result.ShouldBe("first:not-completed");
- }
-
- [Fact]
- public async Task Opt_In_Url_Including_The_Path_Base_Matches()
- {
- // The request path is "/api/..." (the path base is stripped), so this only matches via path base + path.
- Options.CompleteUnitOfWorkOnResponseStartingUrls.Add("/pathbase-test/api/unitofwork-test/CommitBeforeResponseFlush");
-
- var result = await GetResponseAsStringAsync("/pathbase-test/api/unitofwork-test/CommitBeforeResponseFlush");
- result.ShouldBe("first:completed");
- }
}
diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictAspNetCoreModule.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictAspNetCoreModule.cs
index edaa453b2e..ea03453c52 100644
--- a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictAspNetCoreModule.cs
+++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictAspNetCoreModule.cs
@@ -1,10 +1,7 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
+using System.Collections.Generic;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Options;
using OpenIddict.Abstractions;
using OpenIddict.Server;
using Volo.Abp.AspNetCore.MultiTenancy;
@@ -51,40 +48,12 @@ public class AbpOpenIddictAspNetCoreModule : AbpModule
options.RemoveClientIdClaim();
});
- // Complete data written while processing OpenIddict requests before the response starts.
- // Derived from the configured OpenIddict server endpoint paths (including the device endpoint).
- context.Services.AddOptions()
- .Configure>((uowOptions, serverOptions) =>
- {
- foreach (var path in GetServerEndpointPaths(serverOptions.Value))
- {
- if (!uowOptions.CompleteUnitOfWorkOnResponseStartingUrls.Contains(path))
- {
- uowOptions.CompleteUnitOfWorkOnResponseStartingUrls.Add(path);
- }
- }
- });
- }
-
- private static IEnumerable GetServerEndpointPaths(OpenIddictServerOptions serverOptions)
- {
- var endpoints = serverOptions.TokenEndpointUris
- .Concat(serverOptions.AuthorizationEndpointUris)
- .Concat(serverOptions.DeviceAuthorizationEndpointUris)
- .Concat(serverOptions.PushedAuthorizationEndpointUris)
- .Concat(serverOptions.EndSessionEndpointUris)
- .Concat(serverOptions.RevocationEndpointUris)
- .Concat(serverOptions.EndUserVerificationEndpointUris);
-
- foreach (var uri in endpoints)
+ // Complete tokens/authorizations/sessions written while processing OpenIddict requests before the response starts.
+ Configure(options =>
{
- // Normalize the (usually relative) endpoint URI to an absolute path, e.g. "connect/token" -> "/connect/token".
- var path = uri.IsAbsoluteUri ? uri.AbsolutePath : "/" + uri.OriginalString.RemovePreFix("./").TrimStart('/');
- if (path.Length > 1)
- {
- yield return path;
- }
- }
+ options.CompleteUnitOfWorkOnResponseStartingUrls.AddIfNotContains("/connect");
+ options.CompleteUnitOfWorkOnResponseStartingUrls.AddIfNotContains("/device");
+ });
}
private void AddOpenIddictServer(IServiceCollection services)
diff --git a/modules/openiddict/test/Volo.Abp.OpenIddict.AspNetCore.Tests/Volo/Abp/OpenIddict/Integration/OpenIddictTokenEndpoint_Integration_Tests.cs b/modules/openiddict/test/Volo.Abp.OpenIddict.AspNetCore.Tests/Volo/Abp/OpenIddict/Integration/OpenIddictTokenEndpoint_Integration_Tests.cs
index 483e64694b..cf11cffdf3 100644
--- a/modules/openiddict/test/Volo.Abp.OpenIddict.AspNetCore.Tests/Volo/Abp/OpenIddict/Integration/OpenIddictTokenEndpoint_Integration_Tests.cs
+++ b/modules/openiddict/test/Volo.Abp.OpenIddict.AspNetCore.Tests/Volo/Abp/OpenIddict/Integration/OpenIddictTokenEndpoint_Integration_Tests.cs
@@ -34,7 +34,7 @@ public class OpenIddictTokenEndpoint_Integration_Tests : AbpWebApplicationFactor
[Fact]
public async Task Token_Row_Is_Committed_Before_The_Connect_Token_Response_Is_Sent()
{
- // The OpenIddict module opts its endpoint paths (including "/connect/token") in by default.
+ // The OpenIddict module opts "/connect" in by default.
var response = await RequestTokenAsync();
response.StatusCode.ShouldBe(HttpStatusCode.OK);