Feature/re route specific handlers (#269)

* #264 added handlers to config

* #264 added global handlers object and defaut param for method, not sure this is correct api for users yet

* #264 Can now add all sorts of delegating handlers in all sorts of ways

* +semver: breaking #264
This commit is contained in:
Tom Pallister
2018-03-10 21:02:59 +00:00
committed by GitHub
parent a31a3ae0fc
commit 4c840d40a6
24 changed files with 692 additions and 137 deletions

View File

@ -1,8 +0,0 @@
namespace Ocelot.Authentication.Handler
{
public enum SupportedAuthenticationProviders
{
IdentityServer,
Jwt
}
}

View File

@ -1,4 +1,3 @@
using Microsoft.AspNetCore.Builder;
using Ocelot.Middleware.Pipeline;
namespace Ocelot.Authentication.Middleware

View File

@ -1,16 +1,12 @@
using Ocelot.Infrastructure.RequestData;
using Ocelot.Logging;
using Ocelot.Responses;
using Ocelot.Configuration;
namespace Ocelot.Authorisation.Middleware
namespace Ocelot.Authorisation.Middleware
{
using System.Collections.Generic;
using System.Threading.Tasks;
using Errors;
using Microsoft.AspNetCore.Http;
using Ocelot.DownstreamRouteFinder.Middleware;
using Ocelot.Middleware;
using Logging;
using Responses;
using Configuration;
public class AuthorisationMiddleware : OcelotMiddleware
{

View File

@ -2,8 +2,6 @@ using Ocelot.Middleware.Pipeline;
namespace Ocelot.Authorisation.Middleware
{
using Microsoft.AspNetCore.Builder;
public static class AuthorisationMiddlewareMiddlewareExtensions
{
public static IOcelotPipelineBuilder UseAuthorisationMiddleware(this IOcelotPipelineBuilder builder)

View File

@ -34,9 +34,9 @@ namespace Ocelot.Authorisation
var userScopes = values.Data;
List<string> matchesScopes = routeAllowedScopes.Intersect(userScopes).ToList();
var matchesScopes = routeAllowedScopes.Intersect(userScopes).ToList();
if (matchesScopes == null || matchesScopes.Count == 0)
if (matchesScopes.Count == 0)
{
return new ErrorResponse<bool>(new List<Error>
{
@ -48,4 +48,4 @@ namespace Ocelot.Authorisation
return new OkResponse<bool>(true);
}
}
}
}

View File

@ -36,9 +36,12 @@ namespace Ocelot.Configuration.Builder
private readonly List<DownstreamHostAndPort> _downstreamAddresses;
private string _upstreamHost;
private string _key;
private List<string> _delegatingHandlers;
public DownstreamReRouteBuilder()
{
_downstreamAddresses = new List<DownstreamHostAndPort>();
_delegatingHandlers = new List<string>();
}
public DownstreamReRouteBuilder WithDownstreamAddresses(List<DownstreamHostAndPort> downstreamAddresses)
@ -215,6 +218,12 @@ namespace Ocelot.Configuration.Builder
return this;
}
public DownstreamReRouteBuilder WithDelegatingHandlers(List<string> delegatingHandlers)
{
_delegatingHandlers = delegatingHandlers;
return this;
}
public DownstreamReRoute Build()
{
return new DownstreamReRoute(
@ -243,7 +252,8 @@ namespace Ocelot.Configuration.Builder
_isAuthorised,
_authenticationOptions,
new PathTemplate(_downstreamPathTemplate),
_reRouteKey);
_reRouteKey,
_delegatingHandlers);
}
}
}

View File

@ -212,6 +212,7 @@ namespace Ocelot.Configuration.Creator
.WithUpstreamHeaderFindAndReplace(hAndRs.Upstream)
.WithDownstreamHeaderFindAndReplace(hAndRs.Downstream)
.WithUpstreamHost(fileReRoute.UpstreamHost)
.WithDelegatingHandlers(fileReRoute.DelegatingHandlers)
.Build();
return reRoute;

View File

@ -31,8 +31,10 @@ namespace Ocelot.Configuration
bool isAuthorised,
AuthenticationOptions authenticationOptions,
PathTemplate downstreamPathTemplate,
string reRouteKey)
string reRouteKey,
List<string> delegatingHandlers)
{
DelegatingHandlers = delegatingHandlers;
Key = key;
UpstreamPathTemplate = upstreamPathTemplate;
UpstreamHeadersFindAndReplace = upstreamHeadersFindAndReplace ?? new List<HeaderFindAndReplace>();
@ -87,5 +89,6 @@ namespace Ocelot.Configuration
public AuthenticationOptions AuthenticationOptions { get; private set; }
public PathTemplate DownstreamPathTemplate { get; private set; }
public string ReRouteKey { get; private set; }
public List<string> DelegatingHandlers {get;private set;}
}
}

View File

@ -19,6 +19,7 @@ namespace Ocelot.Configuration.File
HttpHandlerOptions = new FileHttpHandlerOptions();
UpstreamHeaderTransform = new Dictionary<string, string>();
DownstreamHostAndPorts = new List<FileHostAndPort>();
DelegatingHandlers = new List<string>();
}
public string DownstreamPathTemplate { get; set; }
@ -44,5 +45,6 @@ namespace Ocelot.Configuration.File
public List<FileHostAndPort> DownstreamHostAndPorts {get;set;}
public string UpstreamHost { get; set; }
public string Key { get;set; }
public List<string> DelegatingHandlers {get;set;}
}
}

View File

@ -3,7 +3,6 @@ using CacheManager.Core;
using System;
using System.Net.Http;
using IdentityServer4.AccessTokenValidation;
using Ocelot.Requester;
namespace Ocelot.DependencyInjection
{
@ -19,6 +18,10 @@ namespace Ocelot.DependencyInjection
IOcelotAdministrationBuilder AddAdministration(string path, Action<IdentityServerAuthenticationOptions> configOptions);
IOcelotBuilder AddDelegatingHandler<T>() where T : DelegatingHandler;
IOcelotBuilder AddSingletonDelegatingHandler<T>(bool global = false)
where T : DelegatingHandler;
IOcelotBuilder AddTransientDelegatingHandler<T>(bool global = false)
where T : DelegatingHandler;
}
}

View File

@ -182,10 +182,41 @@ namespace Ocelot.DependencyInjection
return new OcelotAdministrationBuilder(_services, _configurationRoot);
}
public IOcelotBuilder AddDelegatingHandler<THandler>()
public IOcelotBuilder AddSingletonDelegatingHandler<THandler>(bool global = false)
where THandler : DelegatingHandler
{
if(global)
{
_services.AddSingleton<THandler>();
_services.AddSingleton<GlobalDelegatingHandler>(s => {
var service = s.GetService<THandler>();
return new GlobalDelegatingHandler(service);
});
}
else
{
_services.AddSingleton<DelegatingHandler, THandler>();
}
return this;
}
public IOcelotBuilder AddTransientDelegatingHandler<THandler>(bool global = false)
where THandler : DelegatingHandler
{
_services.AddSingleton<DelegatingHandler, THandler>();
if(global)
{
_services.AddTransient<THandler>();
_services.AddTransient<GlobalDelegatingHandler>(s => {
var service = s.GetService<THandler>();
return new GlobalDelegatingHandler(service);
});
}
else
{
_services.AddTransient<DelegatingHandler, THandler>();
}
return this;
}

View File

@ -1,16 +1,17 @@
using Newtonsoft.Json;
namespace Ocelot.Authentication
{
class BearerToken
{
[JsonProperty("access_token")]
public string AccessToken { get; set; }
[JsonProperty("expires_in")]
public int ExpiresIn { get; set; }
[JsonProperty("token_type")]
public string TokenType { get; set; }
}
}
using Newtonsoft.Json;
namespace Ocelot.Raft
{
[ExcludeFromCoverage]
internal class BearerToken
{
[JsonProperty("access_token")]
public string AccessToken { get; set; }
[JsonProperty("expires_in")]
public int ExpiresIn { get; set; }
[JsonProperty("token_type")]
public string TokenType { get; set; }
}
}

View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using Microsoft.Extensions.DependencyInjection;
using Ocelot.Configuration;
@ -29,13 +30,36 @@ namespace Ocelot.Requester
public Response<List<Func<DelegatingHandler>>> Get(DownstreamReRoute request)
{
var handlersAppliedToAll = _serviceProvider.GetServices<DelegatingHandler>();
var globalDelegatingHandlers = _serviceProvider
.GetServices<GlobalDelegatingHandler>()
.ToList();
var reRouteSpecificHandlers = _serviceProvider
.GetServices<DelegatingHandler>()
.ToList();
var handlers = new List<Func<DelegatingHandler>>();
foreach (var handler in handlersAppliedToAll)
foreach (var handler in globalDelegatingHandlers)
{
handlers.Add(() => handler);
if (GlobalIsInHandlersConfig(request, handler))
{
reRouteSpecificHandlers.Add(handler.DelegatingHandler);
}
else
{
handlers.Add(() => handler.DelegatingHandler);
}
}
if (request.DelegatingHandlers.Any())
{
var sorted = SortByConfigOrder(request, reRouteSpecificHandlers);
foreach (var handler in sorted)
{
handlers.Add(() => handler);
}
}
if (request.HttpHandlerOptions.UseTracing)
@ -57,5 +81,22 @@ namespace Ocelot.Requester
return new OkResponse<List<Func<DelegatingHandler>>>(handlers);
}
private List<DelegatingHandler> SortByConfigOrder(DownstreamReRoute request, List<DelegatingHandler> reRouteSpecificHandlers)
{
return reRouteSpecificHandlers
.Where(x => request.DelegatingHandlers.Contains(x.GetType().Name))
.OrderBy(d =>
{
var type = d.GetType().Name;
var pos = request.DelegatingHandlers.IndexOf(type);
return pos;
}).ToList();
}
private bool GlobalIsInHandlersConfig(DownstreamReRoute request, GlobalDelegatingHandler handler)
{
return request.DelegatingHandlers.Contains(handler.DelegatingHandler.GetType().Name);
}
}
}

View File

@ -15,7 +15,7 @@ namespace Ocelot.Requester
private readonly IOcelotLogger _logger;
private readonly IDelegatingHandlerHandlerFactory _factory;
public HttpClientHttpRequester(IOcelotLoggerFactory loggerFactory,
public HttpClientHttpRequester(IOcelotLoggerFactory loggerFactory,
IHttpClientCache cacheHandlers,
IDelegatingHandlerHandlerFactory house)
{
@ -29,7 +29,7 @@ namespace Ocelot.Requester
var builder = new HttpClientBuilder(_factory);
var cacheKey = GetCacheKey(request);
var httpClient = GetHttpClient(cacheKey, builder, request);
try
@ -72,8 +72,23 @@ namespace Ocelot.Requester
private string GetCacheKey(DownstreamContext request)
{
var baseUrl = $"{request.DownstreamRequest.RequestUri.Scheme}://{request.DownstreamRequest.RequestUri.Authority}";
return baseUrl;
}
}
public class ReRouteDelegatingHandler<T> where T : DelegatingHandler
{
public T DelegatingHandler { get; private set; }
}
public class GlobalDelegatingHandler
{
public GlobalDelegatingHandler(DelegatingHandler delegatingHandler)
{
DelegatingHandler = delegatingHandler;
}
public DelegatingHandler DelegatingHandler { get; private set; }
}
}