Browse Source

Match the path base and normalize OpenIddict opt-in endpoint paths

- Rename completedOnResponseStarting and fix response-start completion comments and docs
pull/26017/head
maliming 1 day ago
parent
commit
f1e28e0ebc
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 2
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AbpAspNetCoreUnitOfWorkOptions.cs
  2. 17
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AbpUnitOfWorkMiddleware.cs
  3. 14
      modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictAspNetCoreModule.cs
  4. 2
      modules/openiddict/test/Volo.Abp.OpenIddict.AspNetCore.Tests/Volo/Abp/OpenIddict/Integration/OpenIddictTokenEndpoint_Integration_Tests.cs

2
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AbpAspNetCoreUnitOfWorkOptions.cs

@ -33,7 +33,7 @@ public class AbpAspNetCoreUnitOfWorkOptions
/// <see cref="CompleteUnitOfWorkOnResponseStarting"/> even when it is globally disabled (for example
/// "/connect" matches "/connect/token" but not "/connections"). A trailing slash is normalized; blank,
/// non-absolute, and root ("/") entries are ignored - use <see cref="CompleteUnitOfWorkOnResponseStarting"/>
/// to enable it for every request.
/// to enable it for every request handled by the middleware.
/// </summary>
public List<string> CompleteUnitOfWorkOnResponseStartingUrls { get; } = new List<string>();
}

17
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AbpUnitOfWorkMiddleware.cs

@ -37,7 +37,7 @@ public class AbpUnitOfWorkMiddleware : AbpMiddlewareBase, ITransientDependency
using (var uow = _unitOfWorkManager.Reserve(UnitOfWork.UnitOfWorkReservationName))
{
var completedOnResponseStarting = false;
var completionAttemptedOnResponseStarting = false;
if (!context.Response.HasStarted && ShouldCompleteOnResponseStarting(context))
{
@ -47,7 +47,7 @@ public class AbpUnitOfWorkMiddleware : AbpMiddlewareBase, ITransientDependency
if (_unitOfWorkManager.Current == uow)
{
// Set before completing so a post-commit failure isn't masked by the completion below.
completedOnResponseStarting = true;
completionAttemptedOnResponseStarting = true;
await uow.CompleteAsync(_cancellationTokenProvider.Token);
}
});
@ -55,7 +55,7 @@ public class AbpUnitOfWorkMiddleware : AbpMiddlewareBase, ITransientDependency
await next(context);
if (!completedOnResponseStarting)
if (!completionAttemptedOnResponseStarting)
{
await uow.CompleteAsync(_cancellationTokenProvider.Token);
}
@ -84,8 +84,15 @@ public class AbpUnitOfWorkMiddleware : AbpMiddlewareBase, ITransientDependency
// Normalize a trailing slash ("/connect/" behaves like "/connect") and ignore non-absolute entries.
var prefix = url.TrimEnd('/');
if (prefix.StartsWith("/", StringComparison.Ordinal) &&
context.Request.Path.StartsWithSegments(prefix, StringComparison.OrdinalIgnoreCase))
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;
}

14
modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictAspNetCoreModule.cs

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc.Razor;
@ -50,7 +51,7 @@ public class AbpOpenIddictAspNetCoreModule : AbpModule
options.RemoveClientIdClaim();
});
// Commit tokens/authorizations/sessions written during sign-in before the response is flushed.
// 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<AbpAspNetCoreUnitOfWorkOptions>()
.Configure<IOptions<OpenIddictServerOptions>>((uowOptions, serverOptions) =>
@ -65,6 +66,8 @@ public class AbpOpenIddictAspNetCoreModule : AbpModule
});
}
private static readonly Uri RootUri = new Uri("http://localhost/");
private static IEnumerable<string> GetServerEndpointPaths(OpenIddictServerOptions serverOptions)
{
var endpoints = serverOptions.TokenEndpointUris
@ -77,10 +80,11 @@ public class AbpOpenIddictAspNetCoreModule : AbpModule
foreach (var uri in endpoints)
{
var path = uri.IsAbsoluteUri ? uri.AbsolutePath : uri.OriginalString;
if (!string.IsNullOrWhiteSpace(path))
// Resolve relative endpoint URIs (e.g. "connect/token" or "./connect/token") to an absolute path.
var path = (uri.IsAbsoluteUri ? uri : new Uri(RootUri, uri)).AbsolutePath;
if (!string.IsNullOrWhiteSpace(path) && path != "/")
{
yield return "/" + path.TrimStart('/');
yield return path;
}
}
}

2
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 "/connect" in by default.
// The OpenIddict module opts its endpoint paths (including "/connect/token") in by default.
var response = await RequestTokenAsync();
response.StatusCode.ShouldBe(HttpStatusCode.OK);

Loading…
Cancel
Save