1

I have an asp.net core 5 app. Recently I have needed to write custom middleware to set a per-request variable (globalization data for adjusting dates). To set this variable, I need to request information from the database using a ProjectId key - this sets the timezone for adjusting dates in the request.

The ProjectId is extracted from the JWT auth token. The problem that I have is that the JWT is not being processed until the end of the middleware chain, even though authentication and authorization are called well ahead of my middleware (LocalizationAndCurrencyMiddleware) - code below.

I placed a breakpoint in

services.AddAuthentication().AddJwtBearer("Custom", o => { });

and it occured after the rest of the middleware, including LocalizationAndCurrencyMiddleware. How can I ensure that the JWT is processed prior to my LocalizationAndCurrencyMiddleware methods.

    public void ConfigureServices(IServiceCollection services)
    {
        var authorizePolicy = new AuthorizationPolicyBuilder()
           .RequireAuthenticatedUser()
           .AddAuthenticationSchemes("Custom")
           .Build();
        services.ConfigureOptions<ConfigureJwtBearerOptions>();
        services.AddAuthentication().AddJwtBearer("Custom", o => { });
        services.AddAuthorization(options =>
        {
            options.DefaultPolicy = authorizePolicy;
        });

        services.AddCors();
        services.AddControllers(config =>
        {
            config.Filters.Add(new AuthorizeFilter(authorizePolicy));
            config.OutputFormatters.OfType<StringOutputFormatter>().Single().SupportedMediaTypes.Add("text/html");
        });

        .......
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        DataSourceLoadOptionsBase.StringToLowerDefault = true;
        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseCors(x => x
            .AllowAnyOrigin()
            .AllowAnyMethod()
            .AllowAnyHeader()
            .WithExposedHeaders(new string[] { "Access-Control-Expose-Headers", "Content-Disposition" }));

        app.UseSerilogRequestLogging();
        app.UseRouting();

        app.UseAuthentication();
        app.UseAuthorization();

        app.UseMiddleware<LocalizationAndCurrencyMiddleware>();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
statler
  • 1,322
  • 2
  • 15
  • 24

1 Answers1

0

It turns out you can actually force authentication to occur in the middleware. I tried a couple of things like the following with no success.

await context.AuthenticateAsync();
await context.AuthenticateAsync("Custom"); //name of my jwt auth

In the end, I had to inject IAuthorizationPolicyProvider and IPolicyEvaluator to get the default policy and authenticate it.

using cpDataORM;
using cpDataServices.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authorization.Policy;
using Microsoft.AspNetCore.Http;
using System.Globalization;
using System.Threading.Tasks;

namespace cpDataASP.Middleware
{
    public class LocalizationAndCurrencyMiddleware
    {
        private readonly RequestDelegate _next;

        public LocalizationAndCurrencyMiddleware(RequestDelegate next)
        {
            _next = next;
        }



        public async Task Invoke(HttpContext context, IUserService _userService, ILoginContextAccessor loginContext, IAuthorizationPolicyProvider policyProvider, IPolicyEvaluator policyEvaluator)
        {
            var policy = await policyProvider.GetDefaultPolicyAsync();
            await policyEvaluator.AuthenticateAsync(policy, context);
            var localizationResources = await _userService.GetLocalizationResources();
            loginContext.Timezone = localizationResources.Timezone;
            CultureInfo.CurrentCulture = localizationResources.Culture;

            await _next.Invoke(context);
        }
    }
}
statler
  • 1,322
  • 2
  • 15
  • 24