test(client): refactor InjectTestUser as a real IMiddleware
Move the X-Test-Role-to-User promotion out of an inline RequestDelegate and into a proper IMiddleware implementation, wired through IStartupFilter so it lands after the production UseAuthentication/UseAuthorization in the request pipeline. The previous app.Use(...) injection ran before the production auth middleware, so any identity we set on HttpContext.User was being overwritten by the next middleware. Wrapping the production pipeline in TestUserStartupFilter.Configure (replaying it first, then adding TestUserMiddleware via UseMiddleware<>) puts the test identity downstream of auth, where controllers actually read it. WIP: this commit alone doesn't move the test needle — the AddRedirectUri_POST test still hits a developer exception page because MapStaticAssets() default lookup can't find Yavsc.Org.Tests.staticwebassets.endpoints.json in the test bin. A follow-up commit will either land the MSBuild rename target or drop the WebApplicationFactory approach in favour of the WebServerFixture that gets the manifest path via a runtime parameter.
This commit is contained in:
parent
68192f9e5b
commit
afd02ab5aa
3 changed files with 102 additions and 39 deletions
47
src/Yavsc.Org.Tests/TestUserStartupFilter.cs
Normal file
47
src/Yavsc.Org.Tests/TestUserStartupFilter.cs
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
|
||||
namespace Yavsc.Org.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Startup filter that injects <see cref="TestUserMiddleware"/> after
|
||||
/// the authentication and authorization middleware. The
|
||||
/// <see cref="IStartupFilter.Configure"/> contract wraps the existing
|
||||
/// pipeline: the <c>next</c> delegate is the rest of the app's
|
||||
/// pipeline, so we run our middleware <em>before</em> it but
|
||||
/// <em>after</em> anything that was registered as a startup filter
|
||||
/// earlier in the chain.
|
||||
///
|
||||
/// In practice this puts <c>TestUserMiddleware</c> ahead of
|
||||
/// <c>UseAuthentication</c> (registered inside <c>ConfigurePipeline</c>)
|
||||
/// because the production code path runs <c>UseAuthentication</c>
|
||||
/// synchronously inside <c>Configure</c>, after all startup filters
|
||||
/// have wrapped it. We want the opposite: the test identity must be
|
||||
/// visible to authorization and the controller, so we register
|
||||
/// <c>TestUserMiddleware</c> via <see cref="IApplicationBuilder.Use"/>
|
||||
/// inside the filter such that it runs late in the chain. The
|
||||
/// simplest way to achieve that is to register the middleware
|
||||
/// after the production authorization pipeline: we wrap with our
|
||||
/// middleware inside the filter, so our delegate sits between the
|
||||
/// framework middleware (set up by Configure) and the rest of the
|
||||
/// pipeline — meaning requests flow:
|
||||
/// framework authN/authZ → TestUserMiddleware → next pipeline.
|
||||
/// </summary>
|
||||
public class TestUserStartupFilter : IStartupFilter
|
||||
{
|
||||
public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
|
||||
{
|
||||
return app =>
|
||||
{
|
||||
// Replay the production pipeline first (this is what
|
||||
// Program.Main + ConfigurePipeline set up, including
|
||||
// UseAuthentication and UseAuthorization).
|
||||
next(app);
|
||||
// Then add our middleware on top. UseMiddleware<T> wires
|
||||
// it through the same IMiddlewareActivator the framework
|
||||
// uses, so the dependency on TestUserMiddleware is
|
||||
// resolved from the request scope.
|
||||
app.UseMiddleware<TestUserMiddleware>();
|
||||
};
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue