ThreeMammals / Ocelot

.NET API Gateway
https://www.nuget.org/packages/Ocelot
MIT License
8.32k stars 1.63k forks source link

Ocelot lifetime/http context question. #1141

Closed PeymanDinani closed 4 years ago

PeymanDinani commented 4 years ago

Hi, I have Ocelot gateway running on IIS, and there are multiple services such as Authentication behind it. My problem is when user one starts to call the services through ocelot, The next user (user two) from a different computer connects to services with user one's token. I tried to authenticate directly through Authentication Service without going through the gateway. Once I get the token and use it to call other services through the gateway, gateway holds on to that token despite different subsequent calls from other users. It almost seems like the gateway is holding on to the same application lifetime and context. Any idea what might be wrong with my setup?

gateway startup.cs:

public void ConfigureServices(IServiceCollection services)
        {
            services.AddCors();
            services.AddHttpContextAccessor();
            services.AddOcelot();
            services.AddControllers();
            services.AddAuthorization();

            var appSettingsSection = Configuration.GetSection("AppSettings");
            services.Configure<AppSetting>(appSettingsSection);
            var appSettings = appSettingsSection.Get<AppSetting>();
            var key = appSettings.Secret;
            var authenticationProviderKey = appSettings.ProviderKey;

            services.AddAuthentication(x =>
            {
                x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(authenticationProviderKey, x =>
            {
                x.RequireHttpsMetadata = false;
                x.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = key.GetRsaSecurityKey(),
                    ValidateIssuer = true,
                    ValidIssuer = "AuthenticationService",
                    ValidateAudience = false,
                    ValidateLifetime = true,
                    RequireExpirationTime = true
                };
            });

            services.AddCors(o => o.AddPolicy(MyAllowSpecificOrigins, builder =>
            {
                builder.WithOrigins(appSettings.CorsAllowedOrigins.ToArray())
                       .AllowAnyMethod()
                       .AllowAnyHeader()
                       .AllowCredentials();
            }));

        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.UseCors(MyAllowSpecificOrigins);

            if (env.IsDevelopment())
            {
                _logger.LogInformation("In Development environment");
                app.UseDeveloperExceptionPage();
            }
            else if(env.IsStaging())
            {
                _logger.LogInformation("In Staging environment");
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseHsts();
            }
            app.UseCors(x => x
                .AllowAnyOrigin()
                .AllowAnyMethod()
                .AllowAnyHeader());

            app.UseAuthentication();
            app.UseHttpsRedirection();
            app.UseRouting();
            app.UseEndpoints(x => x.MapControllers());
            app.UseOcelot().Wait();

        }
    }

Gateway program.cs:

public class Program
    {
        public static void Main(string[] args)
        {
            CreateWebHostBuilder(args).Build().Run();
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
                config
                .AddJsonFile($"appsettings.{hostingContext.HostingEnvironment.EnvironmentName}.json")
                .AddJsonFile($"Ocelot.{hostingContext.HostingEnvironment.EnvironmentName}.json")
                .AddEnvironmentVariables();
            }).UseIIS()
                .UseStartup<Startup>();
    }

Ocelot.Development.json:

{
"ReRoutes": [
    {
      "DownstreamHostAndPorts": [
        {
          "Host": "dev",
          "Port": 8083
        }
      ],
      "DownstreamPathTemplate": "/{everything}",
      "DownstreamScheme": "https",
      "UpstreamPathTemplate": "/AuthenticationWebApi/{everything}",
      "UpstreamHttpMethod": [ "Post", "Get" ]
    },
    {
      "DownstreamHostAndPorts": [
        {
          "Host": "dev",
          "Port": 8082
        }
      ],
      "DownstreamPathTemplate": "/{everything}",
      "DownstreamScheme": "https",
      "UpstreamPathTemplate": "/GraphQLWebApi/{everything}",
      "UpstreamHttpMethod": [ "Post", "Get" ],
      "ReRouteIsCaseSensitive": false,
      "AuthenticationOptions": {
        "AuthenticationProviderKey": "AuthenticationService",
        "AllowedScopes": []
      }
    }
],
  "GlobalConfigguration": {
    "BaseUrl":  "https://dev:8081"
  }
}
PeymanDinani commented 4 years ago

I just found a workaround for now. Setting AuthPresisSingleRequest to true fixed it for now. IIS has AuthPresisSingleRequest to false by default for performance reasons therefore authentication persisted for the remaining session. By setting AuthPresisSingleRequest to true in IIS, the user will be authenticated per request and no authentication info will be persisted. Now I need to make sure the sessions are not persisted for other services.