mirror of
https://github.com/nsnail/Ocelot.git
synced 2025-06-19 17:08:15 +08:00
Merge branch 'release/13.8.0'
This commit is contained in:
@ -1,8 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<RuntimeFrameworkVersion>2.0.0</RuntimeFrameworkVersion>
|
||||
<NETStandardImplicitPackageVersion>2.0.0</NETStandardImplicitPackageVersion>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
<NoPackageAnalysis>true</NoPackageAnalysis>
|
||||
<Description>Provides Ocelot extensions to use the administration API and IdentityService dependencies that come with it</Description>
|
||||
<AssemblyTitle>Ocelot.Administration</AssemblyTitle>
|
||||
@ -29,10 +27,13 @@
|
||||
<ProjectReference Include="..\Ocelot\Ocelot.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.66">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="IdentityServer4.AccessTokenValidation" Version="2.7.0" />
|
||||
<PackageReference Include="IdentityServer4" Version="2.4.0" />
|
||||
<PackageReference Include="IdentityServer4.AccessTokenValidation" Version="3.0.1" />
|
||||
<PackageReference Include="IdentityServer4" Version="3.0.1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Update="Microsoft.SourceLink.GitHub" Version="1.0.0-beta2-19367-01" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
@ -1,18 +1,18 @@
|
||||
namespace Ocelot.Administration
|
||||
{
|
||||
using DependencyInjection;
|
||||
using IdentityServer4.AccessTokenValidation;
|
||||
using IdentityServer4.Models;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Ocelot.Middleware;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using Ocelot.DependencyInjection;
|
||||
using IdentityServer4.AccessTokenValidation;
|
||||
using IdentityServer4.Models;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Ocelot.Middleware;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
|
||||
namespace Ocelot.Administration
|
||||
{
|
||||
public static class OcelotBuilderExtensions
|
||||
{
|
||||
public static IOcelotAdministrationBuilder AddAdministration(this IOcelotBuilder builder, string path, string secret)
|
||||
@ -86,7 +86,7 @@
|
||||
else
|
||||
{
|
||||
//todo - refactor so calls method?
|
||||
var cert = new X509Certificate2(identityServerConfiguration.CredentialsSigningCertificateLocation, identityServerConfiguration.CredentialsSigningCertificatePassword);
|
||||
var cert = new X509Certificate2(identityServerConfiguration.CredentialsSigningCertificateLocation, identityServerConfiguration.CredentialsSigningCertificatePassword, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable);
|
||||
identityServerBuilder.AddSigningCredential(cert);
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<RuntimeFrameworkVersion>2.0.0</RuntimeFrameworkVersion>
|
||||
<NETStandardImplicitPackageVersion>2.0.0</NETStandardImplicitPackageVersion>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
<NoPackageAnalysis>true</NoPackageAnalysis>
|
||||
<Description>Provides Ocelot extensions to use CacheManager.Net</Description>
|
||||
<AssemblyTitle>Ocelot.Cache.CacheManager</AssemblyTitle>
|
||||
@ -28,11 +26,14 @@
|
||||
<ProjectReference Include="..\Ocelot\Ocelot.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.66">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="CacheManager.Core" Version="1.2.0" />
|
||||
<PackageReference Include="CacheManager.Microsoft.Extensions.Configuration" Version="1.2.0" />
|
||||
<PackageReference Include="CacheManager.Microsoft.Extensions.Logging" Version="1.2.0" />
|
||||
<PackageReference Include="CacheManager.Core" Version="2.0.0-beta-1629" />
|
||||
<PackageReference Include="CacheManager.Microsoft.Extensions.Configuration" Version="2.0.0-beta-1629" />
|
||||
<PackageReference Include="CacheManager.Microsoft.Extensions.Logging" Version="2.0.0-beta-1629" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Update="Microsoft.SourceLink.GitHub" Version="1.0.0-beta2-19367-01" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
@ -26,7 +26,7 @@
|
||||
|
||||
public async Task<List<Service>> Get()
|
||||
{
|
||||
var queryResult = await _consul.Health.Service(_config.KeyOfServiceInConsul, string.Empty, false);
|
||||
var queryResult = await _consul.Health.Service(_config.KeyOfServiceInConsul, string.Empty, true);
|
||||
|
||||
var services = new List<Service>();
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
using Configuration.Repository;
|
||||
using global::Consul;
|
||||
using Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Newtonsoft.Json;
|
||||
using Responses;
|
||||
using System;
|
||||
@ -18,29 +19,20 @@
|
||||
private readonly IOcelotLogger _logger;
|
||||
|
||||
public ConsulFileConfigurationRepository(
|
||||
IOptions<FileConfiguration> fileConfiguration,
|
||||
Cache.IOcelotCache<FileConfiguration> cache,
|
||||
IInternalConfigurationRepository repo,
|
||||
IConsulClientFactory factory,
|
||||
IOcelotLoggerFactory loggerFactory)
|
||||
{
|
||||
_logger = loggerFactory.CreateLogger<ConsulFileConfigurationRepository>();
|
||||
_cache = cache;
|
||||
|
||||
var internalConfig = repo.Get();
|
||||
var serviceDiscoveryProvider = fileConfiguration.Value.GlobalConfiguration.ServiceDiscoveryProvider;
|
||||
_configurationKey = string.IsNullOrWhiteSpace(serviceDiscoveryProvider.ConfigurationKey) ? "InternalConfiguration" :
|
||||
serviceDiscoveryProvider.ConfigurationKey;
|
||||
|
||||
_configurationKey = "InternalConfiguration";
|
||||
|
||||
string token = null;
|
||||
|
||||
if (!internalConfig.IsError)
|
||||
{
|
||||
token = internalConfig.Data.ServiceProviderConfiguration.Token;
|
||||
_configurationKey = !string.IsNullOrEmpty(internalConfig.Data.ServiceProviderConfiguration.ConfigurationKey) ?
|
||||
internalConfig.Data.ServiceProviderConfiguration.ConfigurationKey : _configurationKey;
|
||||
}
|
||||
|
||||
var config = new ConsulRegistryConfiguration(internalConfig.Data.ServiceProviderConfiguration.Host,
|
||||
internalConfig.Data.ServiceProviderConfiguration.Port, _configurationKey, token);
|
||||
var config = new ConsulRegistryConfiguration(serviceDiscoveryProvider.Host,
|
||||
serviceDiscoveryProvider.Port, _configurationKey, serviceDiscoveryProvider.Token);
|
||||
|
||||
_consul = factory.Get(config);
|
||||
}
|
||||
|
@ -6,13 +6,13 @@
|
||||
|
||||
public static class ConsulProviderFactory
|
||||
{
|
||||
public static ServiceDiscoveryFinderDelegate Get = (provider, config, name) =>
|
||||
public static ServiceDiscoveryFinderDelegate Get = (provider, config, reRoute) =>
|
||||
{
|
||||
var factory = provider.GetService<IOcelotLoggerFactory>();
|
||||
|
||||
var consulFactory = provider.GetService<IConsulClientFactory>();
|
||||
|
||||
var consulRegistryConfiguration = new ConsulRegistryConfiguration(config.Host, config.Port, name, config.Token);
|
||||
var consulRegistryConfiguration = new ConsulRegistryConfiguration(config.Host, config.Port, reRoute.ServiceName, config.Token);
|
||||
|
||||
var consulServiceDiscoveryProvider = new Consul(consulRegistryConfiguration, factory, consulFactory);
|
||||
|
||||
|
@ -1,8 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<RuntimeFrameworkVersion>2.0.0</RuntimeFrameworkVersion>
|
||||
<NETStandardImplicitPackageVersion>2.0.0</NETStandardImplicitPackageVersion>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
<NoPackageAnalysis>true</NoPackageAnalysis>
|
||||
<Description>Provides Ocelot extensions to use Consul</Description>
|
||||
<AssemblyTitle>Ocelot.Provider.Consul</AssemblyTitle>
|
||||
@ -30,8 +28,11 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Consul" Version="0.7.2.6" />
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.66">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Update="Microsoft.SourceLink.GitHub" Version="1.0.0-beta2-19367-01" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
@ -2,16 +2,17 @@
|
||||
{
|
||||
using Logging;
|
||||
using ServiceDiscovery.Providers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Values;
|
||||
|
||||
public class PollConsul : IServiceDiscoveryProvider
|
||||
public sealed class PollConsul : IServiceDiscoveryProvider, IDisposable
|
||||
{
|
||||
private readonly IOcelotLogger _logger;
|
||||
private readonly IServiceDiscoveryProvider _consulServiceDiscoveryProvider;
|
||||
private readonly Timer _timer;
|
||||
private Timer _timer;
|
||||
private bool _polling;
|
||||
private List<Service> _services;
|
||||
|
||||
@ -34,6 +35,12 @@
|
||||
}, null, pollingInterval, pollingInterval);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_timer?.Dispose();
|
||||
_timer = null;
|
||||
}
|
||||
|
||||
public Task<List<Service>> Get()
|
||||
{
|
||||
return Task.FromResult(_services);
|
||||
|
@ -6,13 +6,13 @@
|
||||
|
||||
public static class EurekaProviderFactory
|
||||
{
|
||||
public static ServiceDiscoveryFinderDelegate Get = (provider, config, name) =>
|
||||
public static ServiceDiscoveryFinderDelegate Get = (provider, config, reRoute) =>
|
||||
{
|
||||
var client = provider.GetService<IDiscoveryClient>();
|
||||
|
||||
if (config.Type?.ToLower() == "eureka" && client != null)
|
||||
{
|
||||
return new Eureka(name, client);
|
||||
return new Eureka(reRoute.ServiceName, client);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -1,8 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<RuntimeFrameworkVersion>2.0.0</RuntimeFrameworkVersion>
|
||||
<NETStandardImplicitPackageVersion>2.0.0</NETStandardImplicitPackageVersion>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
<NoPackageAnalysis>true</NoPackageAnalysis>
|
||||
<Description>Provides Ocelot extensions to use Eureka</Description>
|
||||
<AssemblyTitle>Ocelot.Provider.Eureka</AssemblyTitle>
|
||||
@ -29,9 +27,12 @@
|
||||
<ProjectReference Include="..\Ocelot\Ocelot.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Steeltoe.Discovery.ClientCore" Version="2.2.0" />
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
|
||||
<PackageReference Include="Steeltoe.Discovery.ClientCore" Version="2.3.0" />
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.66">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Update="Microsoft.SourceLink.GitHub" Version="1.0.0-beta2-19367-01" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
@ -12,9 +12,7 @@
|
||||
{
|
||||
public static IOcelotBuilder AddEureka(this IOcelotBuilder builder)
|
||||
{
|
||||
var service = builder.Services.First(x => x.ServiceType == typeof(IConfiguration));
|
||||
var configuration = (IConfiguration)service.ImplementationInstance;
|
||||
builder.Services.AddDiscoveryClient(configuration);
|
||||
builder.Services.AddDiscoveryClient(builder.Configuration);
|
||||
builder.Services.AddSingleton<ServiceDiscoveryFinderDelegate>(EurekaProviderFactory.Get);
|
||||
builder.Services.AddSingleton<OcelotMiddlewareConfigurationDelegate>(EurekaMiddlewareConfigurationProvider.Get);
|
||||
return builder;
|
||||
|
@ -25,8 +25,7 @@ namespace Ocelot.Provider.Kubernetes
|
||||
|
||||
public async Task<List<Service>> Get()
|
||||
{
|
||||
var service = await kubeApi.ServicesV1()
|
||||
.Get(kubeRegistryConfiguration.KeyOfServiceInK8s, kubeRegistryConfiguration.KubeNamespace);
|
||||
var service = await kubeApi.ServicesV1().Get(kubeRegistryConfiguration.KeyOfServiceInK8s, kubeRegistryConfiguration.KubeNamespace);
|
||||
var services = new List<Service>();
|
||||
if (IsValid(service))
|
||||
{
|
||||
|
@ -3,24 +3,25 @@ using Microsoft.Extensions.DependencyInjection;
|
||||
using Ocelot.Logging;
|
||||
using Ocelot.ServiceDiscovery;
|
||||
using System;
|
||||
using Ocelot.Configuration;
|
||||
|
||||
namespace Ocelot.Provider.Kubernetes
|
||||
{
|
||||
public static class KubernetesProviderFactory
|
||||
{
|
||||
public static ServiceDiscoveryFinderDelegate Get = (provider, config, name) =>
|
||||
public static ServiceDiscoveryFinderDelegate Get = (provider, config, reRoute) =>
|
||||
{
|
||||
var factory = provider.GetService<IOcelotLoggerFactory>();
|
||||
return GetkubeProvider(provider, config, name, factory);
|
||||
return GetkubeProvider(provider, config, reRoute, factory);
|
||||
};
|
||||
|
||||
private static ServiceDiscovery.Providers.IServiceDiscoveryProvider GetkubeProvider(IServiceProvider provider, Configuration.ServiceProviderConfiguration config, string name, IOcelotLoggerFactory factory)
|
||||
private static ServiceDiscovery.Providers.IServiceDiscoveryProvider GetkubeProvider(IServiceProvider provider, Configuration.ServiceProviderConfiguration config, DownstreamReRoute reRoute, IOcelotLoggerFactory factory)
|
||||
{
|
||||
var kubeClient = provider.GetService<IKubeApiClient>();
|
||||
var k8sRegistryConfiguration = new KubeRegistryConfiguration()
|
||||
{
|
||||
KeyOfServiceInK8s = name,
|
||||
KubeNamespace = config.Namespace,
|
||||
KeyOfServiceInK8s = reRoute.ServiceName,
|
||||
KubeNamespace = string.IsNullOrEmpty(reRoute.ServiceNamespace) ? config.Namespace : reRoute.ServiceNamespace
|
||||
};
|
||||
|
||||
var k8sServiceDiscoveryProvider = new Kube(k8sRegistryConfiguration, factory, kubeClient);
|
||||
|
@ -1,9 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<RuntimeFrameworkVersion>2.0.0</RuntimeFrameworkVersion>
|
||||
<NETStandardImplicitPackageVersion>2.0.0</NETStandardImplicitPackageVersion>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
<NoPackageAnalysis>true</NoPackageAnalysis>
|
||||
<Product>Ocelot</Product>
|
||||
<Description>Provides Ocelot extensions to use kubernetes</Description>
|
||||
@ -30,12 +28,16 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="KubeClient" Version="2.2.12" />
|
||||
<PackageReference Include="KubeClient.Extensions.DependencyInjection" Version="2.2.12" />
|
||||
<PackageReference Include="KubeClient" Version="2.3.4" />
|
||||
<PackageReference Include="KubeClient.Extensions.DependencyInjection" Version="2.3.4" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Ocelot\Ocelot.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Update="Microsoft.SourceLink.GitHub" Version="1.0.0-beta2-19367-01" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -1,8 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<RuntimeFrameworkVersion>2.0.0</RuntimeFrameworkVersion>
|
||||
<NETStandardImplicitPackageVersion>2.0.0</NETStandardImplicitPackageVersion>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
<NoPackageAnalysis>true</NoPackageAnalysis>
|
||||
<Description>Provides Ocelot extensions to use Polly.NET</Description>
|
||||
<AssemblyTitle>Ocelot.Provider.Polly</AssemblyTitle>
|
||||
@ -29,9 +27,12 @@
|
||||
<ProjectReference Include="..\Ocelot\Ocelot.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.66">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Polly" Version="7.1.0" />
|
||||
<PackageReference Include="Polly" Version="7.1.1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Update="Microsoft.SourceLink.GitHub" Version="1.0.0-beta2-19367-01" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
@ -1,8 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<RuntimeFrameworkVersion>2.0.0</RuntimeFrameworkVersion>
|
||||
<NETStandardImplicitPackageVersion>2.0.0</NETStandardImplicitPackageVersion>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
<NoPackageAnalysis>true</NoPackageAnalysis>
|
||||
<Description>Provides Ocelot extensions to use Rafty</Description>
|
||||
<AssemblyTitle>Ocelot.Provider.Rafty</AssemblyTitle>
|
||||
@ -30,10 +28,13 @@
|
||||
<ProjectReference Include="..\Ocelot.Administration\Ocelot.Administration.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Data.SQLite" Version="2.2.4" />
|
||||
<PackageReference Include="Microsoft.Data.SQLite" Version="3.0.0" />
|
||||
<PackageReference Include="Rafty" Version="0.4.4" />
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.66">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Update="Microsoft.SourceLink.GitHub" Version="1.0.0-beta2-19367-01" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
@ -1,9 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<RuntimeFrameworkVersion>2.0.0</RuntimeFrameworkVersion>
|
||||
<NETStandardImplicitPackageVersion>2.0.0</NETStandardImplicitPackageVersion>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
<NoPackageAnalysis>true</NoPackageAnalysis>
|
||||
<Description>This package provides methods to integrate Butterfly tracing with Ocelot.</Description>
|
||||
<AssemblyTitle>Ocelot.Tracing.Butterfly</AssemblyTitle>
|
||||
@ -33,5 +31,8 @@
|
||||
<PackageReference Include="Butterfly.Client" Version="0.0.8" />
|
||||
<PackageReference Include="Butterfly.Client.AspNetCore" Version="0.0.8" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Update="Microsoft.SourceLink.GitHub" Version="1.0.0-beta2-19367-01" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
public async Task Invoke(DownstreamContext context)
|
||||
{
|
||||
if (IsAuthenticatedRoute(context.DownstreamReRoute))
|
||||
if (!IsOptionsHttpMethod(context) && IsAuthenticatedRoute(context.DownstreamReRoute))
|
||||
{
|
||||
Logger.LogInformation("route is authenticated scopes must be checked");
|
||||
|
||||
@ -52,7 +52,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
if (IsAuthorisedRoute(context.DownstreamReRoute))
|
||||
if (!IsOptionsHttpMethod(context) && IsAuthorisedRoute(context.DownstreamReRoute))
|
||||
{
|
||||
Logger.LogInformation("route is authorised");
|
||||
|
||||
@ -98,6 +98,11 @@
|
||||
private static bool IsAuthorisedRoute(DownstreamReRoute reRoute)
|
||||
{
|
||||
return reRoute.IsAuthorised;
|
||||
}
|
||||
|
||||
private static bool IsOptionsHttpMethod(DownstreamContext context)
|
||||
{
|
||||
return context.HttpContext.Request.Method.ToUpper() == "OPTIONS";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ namespace Ocelot.Configuration.Builder
|
||||
private Dictionary<string, string> _routeClaimRequirement;
|
||||
private bool _isAuthorised;
|
||||
private List<ClaimToThing> _claimToQueries;
|
||||
private List<ClaimToThing> _claimToDownstreamPath;
|
||||
private string _requestIdHeaderKey;
|
||||
private bool _isCached;
|
||||
private CacheOptions _fileCacheOptions;
|
||||
@ -30,6 +31,7 @@ namespace Ocelot.Configuration.Builder
|
||||
private RateLimitOptions _rateLimitOptions;
|
||||
private bool _useServiceDiscovery;
|
||||
private string _serviceName;
|
||||
private string _serviceNamespace;
|
||||
private List<HeaderFindAndReplace> _upstreamHeaderFindAndReplace;
|
||||
private List<HeaderFindAndReplace> _downstreamHeaderFindAndReplace;
|
||||
private readonly List<DownstreamHostAndPort> _downstreamAddresses;
|
||||
@ -126,6 +128,12 @@ namespace Ocelot.Configuration.Builder
|
||||
return this;
|
||||
}
|
||||
|
||||
public DownstreamReRouteBuilder WithClaimsToDownstreamPath(List<ClaimToThing> input)
|
||||
{
|
||||
_claimToDownstreamPath = input;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DownstreamReRouteBuilder WithIsCached(bool input)
|
||||
{
|
||||
_isCached = input;
|
||||
@ -186,6 +194,12 @@ namespace Ocelot.Configuration.Builder
|
||||
return this;
|
||||
}
|
||||
|
||||
public DownstreamReRouteBuilder WithServiceNamespace(string serviceNamespace)
|
||||
{
|
||||
_serviceNamespace = serviceNamespace;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DownstreamReRouteBuilder WithUpstreamHeaderFindAndReplace(List<HeaderFindAndReplace> upstreamHeaderFindAndReplace)
|
||||
{
|
||||
_upstreamHeaderFindAndReplace = upstreamHeaderFindAndReplace;
|
||||
@ -243,6 +257,7 @@ namespace Ocelot.Configuration.Builder
|
||||
_downstreamHeaderFindAndReplace,
|
||||
_downstreamAddresses,
|
||||
_serviceName,
|
||||
_serviceNamespace,
|
||||
_httpHandlerOptions,
|
||||
_useServiceDiscovery,
|
||||
_enableRateLimiting,
|
||||
@ -257,6 +272,7 @@ namespace Ocelot.Configuration.Builder
|
||||
_claimToQueries,
|
||||
_claimsToHeaders,
|
||||
_claimToClaims,
|
||||
_claimToDownstreamPath,
|
||||
_isAuthenticated,
|
||||
_isAuthorised,
|
||||
_authenticationOptions,
|
||||
|
@ -86,6 +86,8 @@ namespace Ocelot.Configuration.Creator
|
||||
|
||||
var claimsToQueries = _claimsToThingCreator.Create(fileReRoute.AddQueriesToRequest);
|
||||
|
||||
var claimsToDownstreamPath = _claimsToThingCreator.Create(fileReRoute.ChangeDownstreamPathTemplate);
|
||||
|
||||
var qosOptions = _qosOptionsCreator.Create(fileReRoute.QoSOptions, fileReRoute.UpstreamPathTemplate, fileReRoute.UpstreamHttpMethod);
|
||||
|
||||
var rateLimitOption = _rateLimitOptionsCreator.Create(fileReRoute.RateLimitOptions, globalConfiguration);
|
||||
@ -114,6 +116,7 @@ namespace Ocelot.Configuration.Creator
|
||||
.WithRouteClaimsRequirement(fileReRoute.RouteClaimsRequirement)
|
||||
.WithIsAuthorised(fileReRouteOptions.IsAuthorised)
|
||||
.WithClaimsToQueries(claimsToQueries)
|
||||
.WithClaimsToDownstreamPath(claimsToDownstreamPath)
|
||||
.WithRequestIdKey(requestIdKey)
|
||||
.WithIsCached(fileReRouteOptions.IsCached)
|
||||
.WithCacheOptions(new CacheOptions(fileReRoute.FileCacheOptions.TtlSeconds, region))
|
||||
@ -126,6 +129,7 @@ namespace Ocelot.Configuration.Creator
|
||||
.WithRateLimitOptions(rateLimitOption)
|
||||
.WithHttpHandlerOptions(httpHandlerOptions)
|
||||
.WithServiceName(fileReRoute.ServiceName)
|
||||
.WithServiceNamespace(fileReRoute.ServiceNamespace)
|
||||
.WithUseServiceDiscovery(fileReRouteOptions.UseServiceDiscovery)
|
||||
.WithUpstreamHeaderFindAndReplace(hAndRs.Upstream)
|
||||
.WithDownstreamHeaderFindAndReplace(hAndRs.Downstream)
|
||||
|
@ -13,6 +13,7 @@ namespace Ocelot.Configuration
|
||||
List<HeaderFindAndReplace> downstreamHeadersFindAndReplace,
|
||||
List<DownstreamHostAndPort> downstreamAddresses,
|
||||
string serviceName,
|
||||
string serviceNamespace,
|
||||
HttpHandlerOptions httpHandlerOptions,
|
||||
bool useServiceDiscovery,
|
||||
bool enableEndpointEndpointRateLimiting,
|
||||
@ -27,6 +28,7 @@ namespace Ocelot.Configuration
|
||||
List<ClaimToThing> claimsToQueries,
|
||||
List<ClaimToThing> claimsToHeaders,
|
||||
List<ClaimToThing> claimsToClaims,
|
||||
List<ClaimToThing> claimsToPath,
|
||||
bool isAuthenticated,
|
||||
bool isAuthorised,
|
||||
AuthenticationOptions authenticationOptions,
|
||||
@ -47,6 +49,7 @@ namespace Ocelot.Configuration
|
||||
DownstreamHeadersFindAndReplace = downstreamHeadersFindAndReplace ?? new List<HeaderFindAndReplace>();
|
||||
DownstreamAddresses = downstreamAddresses ?? new List<DownstreamHostAndPort>();
|
||||
ServiceName = serviceName;
|
||||
ServiceNamespace = serviceNamespace;
|
||||
HttpHandlerOptions = httpHandlerOptions;
|
||||
UseServiceDiscovery = useServiceDiscovery;
|
||||
EnableEndpointEndpointRateLimiting = enableEndpointEndpointRateLimiting;
|
||||
@ -61,6 +64,7 @@ namespace Ocelot.Configuration
|
||||
ClaimsToQueries = claimsToQueries ?? new List<ClaimToThing>();
|
||||
ClaimsToHeaders = claimsToHeaders ?? new List<ClaimToThing>();
|
||||
ClaimsToClaims = claimsToClaims ?? new List<ClaimToThing>();
|
||||
ClaimsToPath = claimsToPath ?? new List<ClaimToThing>();
|
||||
IsAuthenticated = isAuthenticated;
|
||||
IsAuthorised = isAuthorised;
|
||||
AuthenticationOptions = authenticationOptions;
|
||||
@ -76,6 +80,7 @@ namespace Ocelot.Configuration
|
||||
public List<HeaderFindAndReplace> DownstreamHeadersFindAndReplace { get; }
|
||||
public List<DownstreamHostAndPort> DownstreamAddresses { get; }
|
||||
public string ServiceName { get; }
|
||||
public string ServiceNamespace { get; }
|
||||
public HttpHandlerOptions HttpHandlerOptions { get; }
|
||||
public bool UseServiceDiscovery { get; }
|
||||
public bool EnableEndpointEndpointRateLimiting { get; }
|
||||
@ -90,6 +95,7 @@ namespace Ocelot.Configuration
|
||||
public List<ClaimToThing> ClaimsToQueries { get; }
|
||||
public List<ClaimToThing> ClaimsToHeaders { get; }
|
||||
public List<ClaimToThing> ClaimsToClaims { get; }
|
||||
public List<ClaimToThing> ClaimsToPath { get; }
|
||||
public bool IsAuthenticated { get; }
|
||||
public bool IsAuthorised { get; }
|
||||
public AuthenticationOptions AuthenticationOptions { get; }
|
||||
|
@ -11,6 +11,7 @@ namespace Ocelot.Configuration.File
|
||||
AddClaimsToRequest = new Dictionary<string, string>();
|
||||
RouteClaimsRequirement = new Dictionary<string, string>();
|
||||
AddQueriesToRequest = new Dictionary<string, string>();
|
||||
ChangeDownstreamPathTemplate = new Dictionary<string, string>();
|
||||
DownstreamHeaderTransform = new Dictionary<string, string>();
|
||||
FileCacheOptions = new FileCacheOptions();
|
||||
QoSOptions = new FileQoSOptions();
|
||||
@ -34,10 +35,12 @@ namespace Ocelot.Configuration.File
|
||||
public Dictionary<string, string> AddClaimsToRequest { get; set; }
|
||||
public Dictionary<string, string> RouteClaimsRequirement { get; set; }
|
||||
public Dictionary<string, string> AddQueriesToRequest { get; set; }
|
||||
public Dictionary<string, string> ChangeDownstreamPathTemplate { get; set; }
|
||||
public string RequestIdKey { get; set; }
|
||||
public FileCacheOptions FileCacheOptions { get; set; }
|
||||
public bool ReRouteIsCaseSensitive { get; set; }
|
||||
public string ServiceName { get; set; }
|
||||
public string ServiceNamespace { get; set; }
|
||||
public string DownstreamScheme { get; set; }
|
||||
public FileQoSOptions QoSOptions { get; set; }
|
||||
public FileLoadBalancerOptions LoadBalancerOptions { get; set; }
|
||||
|
@ -14,7 +14,7 @@ namespace Ocelot.Configuration.Repository
|
||||
private static readonly object _lock = new object();
|
||||
private const string ConfigurationFileName = "ocelot";
|
||||
|
||||
public DiskFileConfigurationRepository(IHostingEnvironment hostingEnvironment)
|
||||
public DiskFileConfigurationRepository(IWebHostEnvironment hostingEnvironment)
|
||||
{
|
||||
_environmentFilePath = $"{AppContext.BaseDirectory}{ConfigurationFileName}{(string.IsNullOrEmpty(hostingEnvironment.EnvironmentName) ? string.Empty : ".")}{hostingEnvironment.EnvironmentName}.json";
|
||||
|
||||
|
@ -21,8 +21,8 @@
|
||||
.GetServices<ServiceDiscoveryFinderDelegate>()
|
||||
.ToList();
|
||||
|
||||
RuleFor(configuration => configuration.ReRoutes)
|
||||
.SetCollectionValidator(reRouteFluentValidator);
|
||||
RuleForEach(configuration => configuration.ReRoutes)
|
||||
.SetValidator(reRouteFluentValidator);
|
||||
|
||||
RuleFor(configuration => configuration.GlobalConfiguration)
|
||||
.SetValidator(fileGlobalConfigurationFluentValidator);
|
||||
|
@ -80,8 +80,8 @@
|
||||
|
||||
When(reRoute => string.IsNullOrEmpty(reRoute.ServiceName), () =>
|
||||
{
|
||||
RuleFor(reRoute => reRoute.DownstreamHostAndPorts)
|
||||
.SetCollectionValidator(hostAndPortValidator);
|
||||
RuleForEach(reRoute => reRoute.DownstreamHostAndPorts)
|
||||
.SetValidator(hostAndPortValidator);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -29,18 +29,18 @@ namespace Ocelot.DependencyInjection
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static IConfigurationBuilder AddOcelot(this IConfigurationBuilder builder, IHostingEnvironment env)
|
||||
public static IConfigurationBuilder AddOcelot(this IConfigurationBuilder builder, IWebHostEnvironment env)
|
||||
{
|
||||
return builder.AddOcelot(".", env);
|
||||
}
|
||||
|
||||
public static IConfigurationBuilder AddOcelot(this IConfigurationBuilder builder, string folder, IHostingEnvironment env)
|
||||
public static IConfigurationBuilder AddOcelot(this IConfigurationBuilder builder, string folder, IWebHostEnvironment env)
|
||||
{
|
||||
const string primaryConfigFile = "ocelot.json";
|
||||
|
||||
const string globalConfigFile = "ocelot.global.json";
|
||||
|
||||
const string subConfigPattern = @"^ocelot\.[a-zA-Z0-9]+\.json$";
|
||||
const string subConfigPattern = @"^ocelot\.(.*?)\.json$";
|
||||
|
||||
string excludeConfigName = env?.EnvironmentName != null ? $"ocelot.{env.EnvironmentName}.json" : string.Empty;
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Ocelot.Middleware.Multiplexer;
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace Ocelot.DependencyInjection
|
||||
@ -13,6 +14,8 @@ namespace Ocelot.DependencyInjection
|
||||
|
||||
IMvcCoreBuilder MvcCoreBuilder { get; }
|
||||
|
||||
IOcelotBuilder AddDelegatingHandler(Type type, bool global = false);
|
||||
|
||||
IOcelotBuilder AddDelegatingHandler<T>(bool global = false)
|
||||
where T : DelegatingHandler;
|
||||
|
||||
@ -21,5 +24,7 @@ namespace Ocelot.DependencyInjection
|
||||
|
||||
IOcelotBuilder AddTransientDefinedAggregator<T>()
|
||||
where T : class, IDefinedAggregator;
|
||||
|
||||
IOcelotBuilder AddConfigPlaceholders();
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ namespace Ocelot.DependencyInjection
|
||||
using Ocelot.Logging;
|
||||
using Ocelot.Middleware;
|
||||
using Ocelot.Middleware.Multiplexer;
|
||||
using Ocelot.PathManipulation;
|
||||
using Ocelot.QueryStrings;
|
||||
using Ocelot.RateLimit;
|
||||
using Ocelot.Request.Creator;
|
||||
@ -35,6 +36,8 @@ namespace Ocelot.DependencyInjection
|
||||
using Ocelot.Security;
|
||||
using Ocelot.Security.IPSecurity;
|
||||
using Ocelot.ServiceDiscovery;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Reflection;
|
||||
|
||||
@ -91,6 +94,7 @@ namespace Ocelot.DependencyInjection
|
||||
Services.TryAddSingleton<IAddClaimsToRequest, AddClaimsToRequest>();
|
||||
Services.TryAddSingleton<IAddHeadersToRequest, AddHeadersToRequest>();
|
||||
Services.TryAddSingleton<IAddQueriesToRequest, AddQueriesToRequest>();
|
||||
Services.TryAddSingleton<IChangeDownstreamPathTemplate, ChangeDownstreamPathTemplate>();
|
||||
Services.TryAddSingleton<IClaimsParser, ClaimsParser>();
|
||||
Services.TryAddSingleton<IUrlPathToUrlTemplateMatcher, RegExUrlMatcher>();
|
||||
Services.TryAddSingleton<IPlaceholderNameAndValueFinder, UrlPathPlaceholderNameAndValueFinder>();
|
||||
@ -138,7 +142,7 @@ namespace Ocelot.DependencyInjection
|
||||
.AddApplicationPart(assembly)
|
||||
.AddControllersAsServices()
|
||||
.AddAuthorization()
|
||||
.AddJsonFormatters();
|
||||
.AddNewtonsoftJson();
|
||||
|
||||
Services.AddLogging();
|
||||
Services.AddMiddlewareAnalysis();
|
||||
@ -165,6 +169,28 @@ namespace Ocelot.DependencyInjection
|
||||
Services.TryAddSingleton<ISecurityPolicy, IPSecurityPolicy>();
|
||||
}
|
||||
|
||||
public IOcelotBuilder AddDelegatingHandler(Type delegateType, bool global = false)
|
||||
{
|
||||
if (!typeof(DelegatingHandler).IsAssignableFrom(delegateType)) throw new ArgumentOutOfRangeException(nameof(delegateType), delegateType.Name, "It is not a delegatin handler");
|
||||
|
||||
if (global)
|
||||
{
|
||||
Services.AddTransient(delegateType);
|
||||
Services.AddTransient<GlobalDelegatingHandler>(s =>
|
||||
{
|
||||
|
||||
var service = s.GetService(delegateType) as DelegatingHandler;
|
||||
return new GlobalDelegatingHandler(service);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Services.AddTransient(typeof(DelegatingHandler), delegateType);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public IOcelotBuilder AddDelegatingHandler<THandler>(bool global = false)
|
||||
where THandler : DelegatingHandler
|
||||
{
|
||||
@ -184,5 +210,39 @@ namespace Ocelot.DependencyInjection
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public IOcelotBuilder AddConfigPlaceholders()
|
||||
{
|
||||
// see: https://greatrexpectations.com/2018/10/25/decorators-in-net-core-with-dependency-injection
|
||||
var wrappedDescriptor = Services.First(x => x.ServiceType == typeof(IPlaceholders));
|
||||
|
||||
var objectFactory = ActivatorUtilities.CreateFactory(
|
||||
typeof(ConfigAwarePlaceholders),
|
||||
new[] { typeof(IPlaceholders) });
|
||||
|
||||
Services.Replace(ServiceDescriptor.Describe(
|
||||
typeof(IPlaceholders),
|
||||
s => (IPlaceholders) objectFactory(s,
|
||||
new[] {CreateInstance(s, wrappedDescriptor)}),
|
||||
wrappedDescriptor.Lifetime
|
||||
));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private static object CreateInstance(IServiceProvider services, ServiceDescriptor descriptor)
|
||||
{
|
||||
if (descriptor.ImplementationInstance != null)
|
||||
{
|
||||
return descriptor.ImplementationInstance;
|
||||
}
|
||||
|
||||
if (descriptor.ImplementationFactory != null)
|
||||
{
|
||||
return descriptor.ImplementationFactory(services);
|
||||
}
|
||||
|
||||
return ActivatorUtilities.GetServiceOrCreateInstance(services, descriptor.ImplementationType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,9 +7,9 @@ namespace Ocelot.DependencyInjection
|
||||
public static class ServiceCollectionExtensions
|
||||
{
|
||||
public static IOcelotBuilder AddOcelot(this IServiceCollection services)
|
||||
{
|
||||
var service = services.First(x => x.ServiceType == typeof(IConfiguration));
|
||||
var configuration = (IConfiguration)service.ImplementationInstance;
|
||||
{
|
||||
var configuration = services.BuildServiceProvider()
|
||||
.GetRequiredService<IConfiguration>();
|
||||
return new OcelotBuilder(services, configuration);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,52 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using Ocelot.Configuration;
|
||||
using Ocelot.DownstreamRouteFinder.UrlMatcher;
|
||||
using Ocelot.Infrastructure;
|
||||
using Ocelot.Infrastructure.Claims.Parser;
|
||||
using Ocelot.Responses;
|
||||
using Ocelot.Values;
|
||||
|
||||
namespace Ocelot.PathManipulation
|
||||
{
|
||||
public class ChangeDownstreamPathTemplate : IChangeDownstreamPathTemplate
|
||||
{
|
||||
private readonly IClaimsParser _claimsParser;
|
||||
|
||||
public ChangeDownstreamPathTemplate(IClaimsParser claimsParser)
|
||||
{
|
||||
_claimsParser = claimsParser;
|
||||
}
|
||||
|
||||
public Response ChangeDownstreamPath(List<ClaimToThing> claimsToThings, IEnumerable<Claim> claims,
|
||||
DownstreamPathTemplate downstreamPathTemplate, List<PlaceholderNameAndValue> placeholders)
|
||||
{
|
||||
foreach (var config in claimsToThings)
|
||||
{
|
||||
var value = _claimsParser.GetValue(claims, config.NewKey, config.Delimiter, config.Index);
|
||||
|
||||
if (value.IsError)
|
||||
{
|
||||
return new ErrorResponse(value.Errors);
|
||||
}
|
||||
|
||||
var placeholderName = $"{{{config.ExistingKey}}}";
|
||||
|
||||
if (!downstreamPathTemplate.Value.Contains(placeholderName))
|
||||
{
|
||||
return new ErrorResponse(new CouldNotFindPlaceholderError(placeholderName));
|
||||
}
|
||||
|
||||
if (placeholders.Any(ph => ph.Name == placeholderName))
|
||||
{
|
||||
placeholders.RemoveAll(ph => ph.Name == placeholderName);
|
||||
}
|
||||
|
||||
placeholders.Add(new PlaceholderNameAndValue(placeholderName, value.Data));
|
||||
}
|
||||
|
||||
return new OkResponse();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
using Ocelot.Configuration;
|
||||
using Ocelot.DownstreamRouteFinder.UrlMatcher;
|
||||
using Ocelot.Request.Middleware;
|
||||
using Ocelot.Responses;
|
||||
using Ocelot.Values;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
|
||||
namespace Ocelot.PathManipulation
|
||||
{
|
||||
public interface IChangeDownstreamPathTemplate
|
||||
{
|
||||
Response ChangeDownstreamPath(List<ClaimToThing> claimsToThings, IEnumerable<Claim> claims,
|
||||
DownstreamPathTemplate downstreamPathTemplate, List<PlaceholderNameAndValue> placeholders);
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
using Ocelot.Logging;
|
||||
using Ocelot.Middleware;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ocelot.PathManipulation.Middleware
|
||||
{
|
||||
public class ClaimsToDownstreamPathMiddleware : OcelotMiddleware
|
||||
{
|
||||
private readonly OcelotRequestDelegate _next;
|
||||
private readonly IChangeDownstreamPathTemplate _changeDownstreamPathTemplate;
|
||||
|
||||
public ClaimsToDownstreamPathMiddleware(OcelotRequestDelegate next,
|
||||
IOcelotLoggerFactory loggerFactory,
|
||||
IChangeDownstreamPathTemplate changeDownstreamPathTemplate)
|
||||
: base(loggerFactory.CreateLogger<ClaimsToDownstreamPathMiddleware>())
|
||||
{
|
||||
_next = next;
|
||||
_changeDownstreamPathTemplate = changeDownstreamPathTemplate;
|
||||
}
|
||||
|
||||
public async Task Invoke(DownstreamContext context)
|
||||
{
|
||||
if (context.DownstreamReRoute.ClaimsToPath.Any())
|
||||
{
|
||||
Logger.LogInformation($"{context.DownstreamReRoute.DownstreamPathTemplate.Value} has instructions to convert claims to path");
|
||||
var response = _changeDownstreamPathTemplate.ChangeDownstreamPath(context.DownstreamReRoute.ClaimsToPath, context.HttpContext.User.Claims,
|
||||
context.DownstreamReRoute.DownstreamPathTemplate, context.TemplatePlaceholderNameAndValues);
|
||||
|
||||
if (response.IsError)
|
||||
{
|
||||
Logger.LogWarning("there was an error setting queries on context, setting pipeline error");
|
||||
|
||||
SetPipelineError(context, response.Errors);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
await _next.Invoke(context);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
using Ocelot.Middleware.Pipeline;
|
||||
|
||||
namespace Ocelot.PathManipulation.Middleware
|
||||
{
|
||||
public static class ClaimsToDownstreamPathMiddlewareExtensions
|
||||
{
|
||||
public static IOcelotPipelineBuilder UseClaimsToDownstreamPathMiddleware(this IOcelotPipelineBuilder builder)
|
||||
{
|
||||
return builder.UseMiddleware<ClaimsToDownstreamPathMiddleware>();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
namespace Ocelot.Infrastructure.Claims.Parser
|
||||
{
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Responses;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@ -24,7 +24,7 @@
|
||||
|
||||
var splits = claimResponse.Data.Split(delimiter.ToCharArray());
|
||||
|
||||
if (splits.Length < index || index < 0)
|
||||
if (splits.Length <= index || index < 0)
|
||||
{
|
||||
return new ErrorResponse<string>(new CannotFindClaimError($"Cannot find claim for key: {key}, delimiter: {delimiter}, index: {index}"));
|
||||
}
|
||||
@ -55,4 +55,4 @@
|
||||
return new ErrorResponse<string>(new CannotFindClaimError($"Cannot find claim for key: {key}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
61
src/Ocelot/Infrastructure/ConfigAwarePlaceholders.cs
Normal file
61
src/Ocelot/Infrastructure/ConfigAwarePlaceholders.cs
Normal file
@ -0,0 +1,61 @@
|
||||
namespace Ocelot.Infrastructure
|
||||
{
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Request.Middleware;
|
||||
using Responses;
|
||||
|
||||
public class ConfigAwarePlaceholders : IPlaceholders
|
||||
{
|
||||
private readonly IConfiguration _configuration;
|
||||
private readonly IPlaceholders _placeholders;
|
||||
|
||||
public ConfigAwarePlaceholders(IConfiguration configuration, IPlaceholders placeholders)
|
||||
{
|
||||
_configuration = configuration;
|
||||
_placeholders = placeholders;
|
||||
}
|
||||
|
||||
public Response<string> Get(string key)
|
||||
{
|
||||
var placeholderResponse = _placeholders.Get(key);
|
||||
|
||||
if (!placeholderResponse.IsError)
|
||||
{
|
||||
return placeholderResponse;
|
||||
}
|
||||
|
||||
return GetFromConfig(CleanKey(key));
|
||||
}
|
||||
|
||||
public Response<string> Get(string key, DownstreamRequest request)
|
||||
{
|
||||
var placeholderResponse = _placeholders.Get(key, request);
|
||||
|
||||
if (!placeholderResponse.IsError)
|
||||
{
|
||||
return placeholderResponse;
|
||||
}
|
||||
|
||||
return GetFromConfig(CleanKey(key));
|
||||
}
|
||||
|
||||
public Response Add(string key, Func<Response<string>> func)
|
||||
=> _placeholders.Add(key, func);
|
||||
|
||||
public Response Remove(string key)
|
||||
=> _placeholders.Remove(key);
|
||||
|
||||
private string CleanKey(string key)
|
||||
=> Regex.Replace(key, @"[{}]", string.Empty, RegexOptions.None);
|
||||
|
||||
private Response<string> GetFromConfig(string key)
|
||||
{
|
||||
var valueFromConfig = _configuration[key];
|
||||
return valueFromConfig == null
|
||||
? (Response<string>) new ErrorResponse<string>(new CouldNotFindPlaceholderError(key))
|
||||
: new OkResponse<string>(valueFromConfig);
|
||||
}
|
||||
}
|
||||
}
|
@ -8,53 +8,83 @@ namespace Ocelot.Logging
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly IRequestScopedDataRepository _scopedDataRepository;
|
||||
private readonly Func<string, Exception, string> _func;
|
||||
|
||||
public AspDotNetLogger(ILogger logger, IRequestScopedDataRepository scopedDataRepository)
|
||||
{
|
||||
_logger = logger;
|
||||
_scopedDataRepository = scopedDataRepository;
|
||||
_scopedDataRepository = scopedDataRepository;
|
||||
_func = (state, exception) =>
|
||||
{
|
||||
if (exception == null)
|
||||
{
|
||||
return state;
|
||||
}
|
||||
else
|
||||
{
|
||||
return $"{state}, exception: {exception}";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void LogTrace(string message)
|
||||
{
|
||||
{
|
||||
var requestId = GetOcelotRequestId();
|
||||
var previousRequestId = GetOcelotPreviousRequestId();
|
||||
_logger.LogTrace("requestId: {requestId}, previousRequestId: {previousRequestId}, message: {message}", requestId, previousRequestId, message);
|
||||
var previousRequestId = GetOcelotPreviousRequestId();
|
||||
|
||||
var state = $"requestId: {requestId}, previousRequestId: {previousRequestId}, message: {message}";
|
||||
|
||||
_logger.Log(LogLevel.Trace, default(EventId), state, null, _func);
|
||||
}
|
||||
|
||||
public void LogDebug(string message)
|
||||
{
|
||||
{
|
||||
var requestId = GetOcelotRequestId();
|
||||
var previousRequestId = GetOcelotPreviousRequestId();
|
||||
_logger.LogDebug("requestId: {requestId}, previousRequestId: {previousRequestId}, message: {message}", requestId, previousRequestId, message);
|
||||
var previousRequestId = GetOcelotPreviousRequestId();
|
||||
|
||||
var state = $"requestId: {requestId}, previousRequestId: {previousRequestId}, message: {message}";
|
||||
|
||||
_logger.Log(LogLevel.Debug, default(EventId), state, null, _func);
|
||||
}
|
||||
|
||||
public void LogInformation(string message)
|
||||
{
|
||||
{
|
||||
var requestId = GetOcelotRequestId();
|
||||
var previousRequestId = GetOcelotPreviousRequestId();
|
||||
_logger.LogInformation("requestId: {requestId}, previousRequestId: {previousRequestId}, message: {message}", requestId, previousRequestId, message);
|
||||
var previousRequestId = GetOcelotPreviousRequestId();
|
||||
|
||||
var state = $"requestId: {requestId}, previousRequestId: {previousRequestId}, message: {message}";
|
||||
|
||||
_logger.Log(LogLevel.Information, default(EventId), state, null, _func);
|
||||
}
|
||||
|
||||
public void LogWarning(string message)
|
||||
{
|
||||
var requestId = GetOcelotRequestId();
|
||||
var previousRequestId = GetOcelotPreviousRequestId();
|
||||
_logger.LogWarning("requestId: {requestId}, previousRequestId: {previousRequestId}, message: {message}", requestId, previousRequestId, message);
|
||||
var previousRequestId = GetOcelotPreviousRequestId();
|
||||
|
||||
var state = $"requestId: {requestId}, previousRequestId: {previousRequestId}, message: {message}";
|
||||
|
||||
_logger.Log(LogLevel.Warning, default(EventId), state, null, _func);
|
||||
}
|
||||
|
||||
public void LogError(string message, Exception exception)
|
||||
{
|
||||
var requestId = GetOcelotRequestId();
|
||||
var previousRequestId = GetOcelotPreviousRequestId();
|
||||
_logger.LogError("requestId: {requestId}, previousRequestId: {previousRequestId}, message: {message}, exception: {exception}", requestId, previousRequestId, message, exception);
|
||||
var previousRequestId = GetOcelotPreviousRequestId();
|
||||
|
||||
var state = $"requestId: {requestId}, previousRequestId: {previousRequestId}, message: {message}";
|
||||
|
||||
_logger.Log(LogLevel.Error,default(EventId), state, exception, _func);
|
||||
}
|
||||
|
||||
public void LogCritical(string message, Exception exception)
|
||||
{
|
||||
var requestId = GetOcelotRequestId();
|
||||
var previousRequestId = GetOcelotPreviousRequestId();
|
||||
_logger.LogCritical("requestId: {requestId}, previousRequestId: {previousRequestId}, message: {message}, exception: {exception}", requestId, previousRequestId, message, exception);
|
||||
var previousRequestId = GetOcelotPreviousRequestId();
|
||||
|
||||
var state = $"requestId: {requestId}, previousRequestId: {previousRequestId}, message: {message}";
|
||||
|
||||
_logger.Log(LogLevel.Critical, default(EventId), state, exception, _func);
|
||||
}
|
||||
|
||||
private string GetOcelotRequestId()
|
||||
@ -81,4 +111,4 @@ namespace Ocelot.Logging
|
||||
return requestId.Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -178,7 +178,7 @@
|
||||
|
||||
private static void ConfigureDiagnosticListener(IApplicationBuilder builder)
|
||||
{
|
||||
var env = builder.ApplicationServices.GetService<IHostingEnvironment>();
|
||||
var env = builder.ApplicationServices.GetService<IWebHostEnvironment>();
|
||||
var listener = builder.ApplicationServices.GetService<OcelotDiagnosticListener>();
|
||||
var diagnosticListener = builder.ApplicationServices.GetService<DiagnosticListener>();
|
||||
diagnosticListener.SubscribeWithAdapter(listener);
|
||||
|
@ -79,12 +79,12 @@ namespace Ocelot.Middleware.Pipeline
|
||||
var diagnosticListener = (DiagnosticListener)app.ApplicationServices.GetService(typeof(DiagnosticListener));
|
||||
var middlewareName = ocelotDelegate.Target.GetType().Name;
|
||||
|
||||
OcelotRequestDelegate wrapped = context =>
|
||||
OcelotRequestDelegate wrapped = async context =>
|
||||
{
|
||||
try
|
||||
{
|
||||
Write(diagnosticListener, "Ocelot.MiddlewareStarted", middlewareName, context);
|
||||
return ocelotDelegate(context);
|
||||
await ocelotDelegate(context);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -7,6 +7,7 @@ using Ocelot.DownstreamUrlCreator.Middleware;
|
||||
using Ocelot.Errors.Middleware;
|
||||
using Ocelot.Headers.Middleware;
|
||||
using Ocelot.LoadBalancer.Middleware;
|
||||
using Ocelot.PathManipulation.Middleware;
|
||||
using Ocelot.QueryStrings.Middleware;
|
||||
using Ocelot.RateLimit.Middleware;
|
||||
using Ocelot.Request.Middleware;
|
||||
@ -118,6 +119,8 @@ namespace Ocelot.Middleware.Pipeline
|
||||
// Now we can run any claims to query string transformation middleware
|
||||
builder.UseClaimsToQueryStringMiddleware();
|
||||
|
||||
builder.UseClaimsToDownstreamPathMiddleware();
|
||||
|
||||
// Get the load balancer for this request
|
||||
builder.UseLoadBalancingMiddleware();
|
||||
|
||||
|
@ -1,8 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<RuntimeFrameworkVersion>2.0.0</RuntimeFrameworkVersion>
|
||||
<NETStandardImplicitPackageVersion>2.0.0</NETStandardImplicitPackageVersion>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
<NoPackageAnalysis>true</NoPackageAnalysis>
|
||||
<Description>Ocelot is an API Gateway. The project is aimed at people using .NET running a micro services / service orientated architecture that need a unified point of entry into their system. In particular I want easy integration with IdentityServer reference and bearer tokens. reference tokens. Ocelot is a bunch of middlewares in a specific order. Ocelot manipulates the HttpRequest object into a state specified by its configuration until it reaches a request builder middleware where it creates a HttpRequestMessage object which is used to make a request to a downstream service. The middleware that makes the request is the last thing in the Ocelot pipeline. It does not call the next middleware. The response from the downstream service is stored in a per request scoped repository and retrived as the requests goes back up the Ocelot pipeline. There is a piece of middleware that maps the HttpResponseMessage onto the HttpResponse object and that is returned to the client. That is basically it with a bunch of other features.</Description>
|
||||
<AssemblyTitle>Ocelot</AssemblyTitle>
|
||||
@ -25,16 +23,20 @@
|
||||
<DebugType>full</DebugType>
|
||||
<DebugSymbols>True</DebugSymbols>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentValidation" Version="8.4.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.MiddlewareAnalysis" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DiagnosticAdapter" Version="2.2.0">
|
||||
<PackageReference Include="FluentValidation" Version="8.5.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.MiddlewareAnalysis" Version="3.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DiagnosticAdapter" Version="3.0.0">
|
||||
<NoWarn>NU1701</NoWarn>
|
||||
</PackageReference>
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.0.0" />
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.66">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Update="Microsoft.SourceLink.GitHub" Version="1.0.0-beta2-19367-01" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -4,5 +4,5 @@ namespace Ocelot.ServiceDiscovery
|
||||
using Providers;
|
||||
using System;
|
||||
|
||||
public delegate IServiceDiscoveryProvider ServiceDiscoveryFinderDelegate(IServiceProvider provider, ServiceProviderConfiguration config, string key);
|
||||
public delegate IServiceDiscoveryProvider ServiceDiscoveryFinderDelegate(IServiceProvider provider, ServiceProviderConfiguration config, DownstreamReRoute reRoute);
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ namespace Ocelot.ServiceDiscovery
|
||||
{
|
||||
if (reRoute.UseServiceDiscovery)
|
||||
{
|
||||
return GetServiceDiscoveryProvider(serviceConfig, reRoute.ServiceName);
|
||||
return GetServiceDiscoveryProvider(serviceConfig, reRoute);
|
||||
}
|
||||
|
||||
var services = new List<Service>();
|
||||
@ -42,17 +42,17 @@ namespace Ocelot.ServiceDiscovery
|
||||
return new OkResponse<IServiceDiscoveryProvider>(new ConfigurationServiceProvider(services));
|
||||
}
|
||||
|
||||
private Response<IServiceDiscoveryProvider> GetServiceDiscoveryProvider(ServiceProviderConfiguration config, string key)
|
||||
private Response<IServiceDiscoveryProvider> GetServiceDiscoveryProvider(ServiceProviderConfiguration config, DownstreamReRoute reRoute)
|
||||
{
|
||||
if (config.Type?.ToLower() == "servicefabric")
|
||||
{
|
||||
var sfConfig = new ServiceFabricConfiguration(config.Host, config.Port, key);
|
||||
var sfConfig = new ServiceFabricConfiguration(config.Host, config.Port, reRoute.ServiceName);
|
||||
return new OkResponse<IServiceDiscoveryProvider>(new ServiceFabricServiceDiscoveryProvider(sfConfig));
|
||||
}
|
||||
|
||||
if (_delegates != null)
|
||||
{
|
||||
var provider = _delegates?.Invoke(_provider, config, key);
|
||||
var provider = _delegates?.Invoke(_provider, config, reRoute);
|
||||
|
||||
if (provider.GetType().Name.ToLower() == config.Type.ToLower())
|
||||
{
|
||||
|
@ -47,6 +47,15 @@ namespace Ocelot.WebSockets.Middleware
|
||||
await destination.CloseOutputAsync(WebSocketCloseStatus.EndpointUnavailable, null, cancellationToken);
|
||||
return;
|
||||
}
|
||||
catch (WebSocketException e)
|
||||
{
|
||||
if (e.WebSocketErrorCode == WebSocketError.ConnectionClosedPrematurely)
|
||||
{
|
||||
await destination.CloseOutputAsync(WebSocketCloseStatus.EndpointUnavailable, null, cancellationToken);
|
||||
return;
|
||||
}
|
||||
throw;
|
||||
}
|
||||
|
||||
if (result.MessageType == WebSocketMessageType.Close)
|
||||
{
|
||||
|
Reference in New Issue
Block a user