Asp Net core endpoint routing principle

Endpoint routing first appeared in asp Net core2.2, in asp Net core3.0 promoted to a first-class citizen.

Motivation of Endpoint Routing

Before the emergence of endpoint routing, we usually define MVC middleware resolution routing at the end of the request processing pipeline. This means that in the processing pipeline, the middleware before MVC middleware will not be able to obtain routing information.

Routing information is very useful for some middleware, such as CORS and authentication middleware (routing information may be used in the authentication process).

At the same time, endpoint routing abstracts the concept of endpoint, decouples the routing matching logic and requests distribution.

Endpoint Routing Middleware

It consists of a pair of middleware:

  1. UseRouting adds route matching to the middleware pipeline. The middleware views the set of endpoints defined in the application and selects the best match according to the request.
  2. UseEndpoints adds endpoint execution to the middleware pipeline.
    MapGet, MapPost and other methods connect the processing logic to the routing system;
    Other methods use asp Net core framework features connect to the routing system.
  • MapRazorPages for Razor Pages
  • MapControllers for controllers
  • MapHub< THub> for SignalR
  • MapGrpcService< TService> for gRPC

The middleware upstream of this pair of middleware: it is always unable to perceive the Endpoint;
The middleware between these middleware pairs will be aware of the Endpoint and have the ability to execute additional processing logic;
UseEndpoint is an endpoint middleware;
If there is no match, enter the middleware after UseEndpoint.


The authentication and authorization middleware placed between UseRouting and UseEndpoints can:
Sensing the matched Endpoint information; Apply the authorization policy before scheduling to the Endpoint.

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    // Matches request to an endpoint.
    app.UseRouting();

    // Endpoint aware middleware. 
    // Middleware can use metadata from the matched endpoint.
    app.UseAuthentication();
    app.UseAuthorization();

    // Execute the matched endpoint.
    app.UseEndpoints(endpoints =>
    {
        // Configure the Health Check endpoint and require an authorized user.
        endpoints.MapHealthChecks("/healthz").RequireAuthorization();

        // Configure another endpoint, no authorization requirements.
        endpoints.MapGet("/", async context =>
        {
            await context.Response.WriteAsync("Hello World!");
        });
    });
}

The above defines the health check in /health. The endpoint defines IAuthorizeDatametadata, which requires authentication before performing the health check.

We add a bit of saliva code between UseRouting and UseEndpoints: perception endpoint:

            app.Use(next => context =>
            {
                var endpoint = context.GetEndpoint();
                if (endpoint is null)
                {
                    return Task.CompletedTask;
                }
                Console.WriteLine($"Endpoint: {endpoint.DisplayName}");

                if (endpoint is RouteEndpoint routeEndpoint)
                {
                    Console.WriteLine("Endpoint has route pattern: " +
                        routeEndpoint.RoutePattern.RawText);
                }

                foreach (var metadata in endpoint.Metadata)
                {
                    Console.WriteLine($"Endpoint has metadata: {metadata}");
                }
                return next(context);
            });

When /healthz is requested, the AuthorizeAttribute metadata is sensed

Therefore, it is assumed that the authentication and authorization middleware must react to the AuthorizeAttribute metadata if it wants to work on /healthz.

So I read the GithubAuthorizationMiddleware3.0 source code and found that I did pay attention to Endpoint

// ----Intercepted from https://github.com/dotnet/aspnetcore/blob/master/src/Security/Authorization/Policy/src/AuthorizationMiddleware.cs-----
if (endpoint != null)
{
    context.Items[AuthorizationMiddlewareInvokedWithEndpointKey] = AuthorizationMiddlewareWithEndpointInvokedValue;
}
var authorizeData = endpoint?.Metadata.GetOrderedMetadata<IAuthorizeData>() ?? Array.Empty<IAuthorizeData>();
var policy = await AuthorizationPolicy.CombineAsync(_policyProvider, authorizeData);
if (policy == null)
{
     await _next(context);
     return;
}
var policyEvaluator = context.RequestServices.GetRequiredService<IPolicyEvaluator>();
......

The AuthorizeAttribute does implement the IAuthorizeData interface.

binggo, guess to get the source code verification.

conclusion

Endpoint Routing: allow asp Net core application determines the endpoint to be dispatched at the early stage of the middleware pipeline,
So that subsequent middleware can use this information to provide functions that cannot be provided by the current pipeline configuration.

This enables asp Net core framework is more flexible and strengthens the concept of endpoint. It decouples the routing matching and resolution functions from the endpoint distribution functions.

Tags: .NET

Posted by c_shelswell on Mon, 30 May 2022 12:47:07 +0530