Initial Commit ...
This commit is contained in:
@@ -0,0 +1,182 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using xCommons.Constants;
|
||||
using xCommons.Extensions;
|
||||
using xIdentityModels.Extensions;
|
||||
using xIdentityService.Interfaces;
|
||||
|
||||
namespace xIdentityService.Middlewares {
|
||||
public partial class XIdentityTokenRefresherMiddleware {
|
||||
//
|
||||
#region Properties ...
|
||||
private readonly ILogger logger;
|
||||
private readonly RequestDelegate next;
|
||||
private readonly IXTokenProvider tokenProvider;
|
||||
private readonly IXIdentityProvider identityProvider;
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Constructor ...
|
||||
public XIdentityTokenRefresherMiddleware (
|
||||
RequestDelegate next,
|
||||
ILoggerFactory loggerFactory,
|
||||
IXTokenProvider tokenProvider,
|
||||
IXIdentityProvider identityProvider
|
||||
) {
|
||||
//
|
||||
this.next = next;
|
||||
this.tokenProvider = tokenProvider;
|
||||
this.identityProvider = identityProvider;
|
||||
this.logger = loggerFactory
|
||||
.CreateLogger<XIdentityTokenRefresherMiddleware> ();
|
||||
}
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Actions ...
|
||||
public async Task Invoke (HttpContext context) {
|
||||
//
|
||||
// Handle Request ...
|
||||
await HandleRequest (context);
|
||||
|
||||
//
|
||||
// Do Main Task ...
|
||||
try {
|
||||
await next.Invoke (context);
|
||||
} catch (Exception ex) {
|
||||
logger.LogError ($"Error: {ex.Message}");
|
||||
}
|
||||
|
||||
//
|
||||
// Handle Response ...
|
||||
await HandleResponse (context);
|
||||
}
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Private ...
|
||||
private async Task HandleRequest (HttpContext context) {
|
||||
//
|
||||
// Log ...
|
||||
logger.LogInformation ($"Start Process Request ...");
|
||||
|
||||
//
|
||||
// Check Access Token ...
|
||||
var hasAccessToken = HasAccessToken (context);
|
||||
if (!hasAccessToken) {
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Check Access Token ...
|
||||
var accessToken = GetAccessToken (context);
|
||||
var isExists = await tokenProvider
|
||||
.IsTokenExists (accessToken);
|
||||
if (!isExists) {
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Try Check is Refreshable ...
|
||||
var tokens = await tokenProvider
|
||||
.RetrieveToken (accessToken);
|
||||
if (tokens.IsNull ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Check is Expired or Refreshable ...
|
||||
var isRefreshable = tokens.IsRefreshable ();
|
||||
if (!isRefreshable) {
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Refresh Token ...
|
||||
var refreshedTokens = await identityProvider
|
||||
.RefreshTokens (tokens);
|
||||
if (refreshedTokens.IsNull ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Set Refreshed AccessToken to Request ...
|
||||
context
|
||||
.Request
|
||||
.Headers[XAuthorization.Header] =
|
||||
$"{XAuthorization.TokenIdentifier}{refreshedTokens.AccessToken}";
|
||||
}
|
||||
|
||||
private async Task HandleResponse (HttpContext context) {
|
||||
//
|
||||
// Log ...
|
||||
logger.LogInformation ($"Start Process Response ...");
|
||||
|
||||
//
|
||||
await Task.Run (() => { });
|
||||
}
|
||||
|
||||
private bool HasAccessToken (HttpContext context) {
|
||||
//
|
||||
// Check Headers ...
|
||||
if (context.IsNull () ||
|
||||
context.Request.IsNull () ||
|
||||
context.Request.Headers.IsNull ()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
var result = context
|
||||
.Request
|
||||
.Headers
|
||||
.ContainsKey (
|
||||
XAuthorization.Header
|
||||
);
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
private string GetAccessToken (HttpContext context) {
|
||||
//
|
||||
var hasAccessToken = HasAccessToken (context);
|
||||
if (!hasAccessToken) {
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
//
|
||||
// Get Result ...
|
||||
var result = context
|
||||
.Request
|
||||
.Headers[
|
||||
XAuthorization.Header
|
||||
];
|
||||
result = result
|
||||
.ToString ()
|
||||
.Replace (
|
||||
XAuthorization.TokenIdentifier,
|
||||
""
|
||||
);
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provide all DI Requirements for XIdentityTokenRefresher Middleware
|
||||
/// </summary>
|
||||
public static class XIdentityTokenRefresherDIHelper {
|
||||
/// <summary>
|
||||
/// Use XTokenValidator Middleware
|
||||
/// </summary>
|
||||
/// <param name="app"></param>
|
||||
public static void UseXIdentityTokenRefresher (this IApplicationBuilder app) {
|
||||
app.UseMiddleware<XIdentityTokenRefresherMiddleware> ();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,827 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using IdentityModel;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.WebUtilities;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using xCommons.Extensions;
|
||||
using xExceptions.Constants;
|
||||
using xIdentityService.Configuration;
|
||||
using xIdentityService.Constants;
|
||||
using xIdentityService.Interfaces;
|
||||
using xIdentityService.Providers;
|
||||
using xModels.Base;
|
||||
|
||||
namespace xIdentityService.Middlewares {
|
||||
/// <summary>
|
||||
/// Proxy Server Middleware ...
|
||||
/// </summary>
|
||||
public class XProxyMiddleware : XBaseClass {
|
||||
//
|
||||
#region Pros ...
|
||||
private readonly HttpClient HTTP_CLIENT;
|
||||
private readonly RequestDelegate NEXT_MIDDLEWARE;
|
||||
private readonly XProxyConfiguration CONFIGURATION;
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Constructor ...
|
||||
public XProxyMiddleware (
|
||||
ILoggerFactory loggerFactory,
|
||||
RequestDelegate nextMiddleware,
|
||||
XProxyConfiguration configuration,
|
||||
IHttpClientFactory httpClientFactory
|
||||
) : base (loggerFactory) {
|
||||
//
|
||||
this.CONFIGURATION = configuration;
|
||||
this.NEXT_MIDDLEWARE = nextMiddleware;
|
||||
|
||||
//
|
||||
// Create Http Client ...
|
||||
this.HTTP_CLIENT = httpClientFactory
|
||||
.CreateClient (XProxyConstants.XPROXY_HTTP_CLIENT);
|
||||
|
||||
//
|
||||
// Logging Server Configuration ...
|
||||
LogXProxyServerConfig ();
|
||||
}
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Public ...
|
||||
public async Task InvokeAsync (HttpContext context) {
|
||||
//
|
||||
#region Bussiness Logic ...
|
||||
//
|
||||
var routeDescriptor = GetRouteDescriptor (context.Request);
|
||||
if (!routeDescriptor.IsNull ()) {
|
||||
//
|
||||
#region Handle Authorization ...
|
||||
//
|
||||
try {
|
||||
//
|
||||
// Handle XPowered ...
|
||||
if (routeDescriptor.EnableXPoweredByAthorization) {
|
||||
//
|
||||
var isPoweredByPass = context.Request.Headers
|
||||
.Any (h => h.Key
|
||||
.ToNormalString () == xCommons.Constants.XAuthorization.XPoweredBy
|
||||
.ToNormalString () &&
|
||||
h.Value
|
||||
.ToString ()
|
||||
.ToNormalString () == CONFIGURATION.XPoweredValue
|
||||
.ToNormalString ()
|
||||
);
|
||||
|
||||
//
|
||||
if (!isPoweredByPass) {
|
||||
ThrowNotAuthorizedException ();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Handle EndableAuthorization ...
|
||||
if (routeDescriptor.EnableAuthorization) {
|
||||
//
|
||||
// Retrieve User Info for Authentication ...
|
||||
var userName = context.User.Identity.Name;
|
||||
var isUserAuthenticated = !userName.IsNull () &&
|
||||
context.User.Identity.IsAuthenticated;
|
||||
if (!isUserAuthenticated &&
|
||||
!routeDescriptor.AllowedScopes.HasChild ()
|
||||
) {
|
||||
ThrowNotAuthorizedException ();
|
||||
}
|
||||
|
||||
//
|
||||
// Check Allowed Scopes Authorization ...
|
||||
if (routeDescriptor.AllowedScopes.HasChild ()) {
|
||||
//
|
||||
var scopeClaims = context.User.Claims
|
||||
.Where (c => c.Type == JwtClaimTypes.Scope)
|
||||
.Select (c => c.Value);
|
||||
var isScopePassed = scopeClaims.HasChild () &&
|
||||
scopeClaims.Any (c => routeDescriptor.AllowedScopes
|
||||
.Any (allowedScope => allowedScope
|
||||
.ToNormalString () == c
|
||||
.ToNormalString ()
|
||||
)
|
||||
);
|
||||
if (!isScopePassed) {
|
||||
ThrowNotAuthorizedException ();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Check Allowed Roles Authorization ...
|
||||
if (
|
||||
isUserAuthenticated &&
|
||||
routeDescriptor.AllowedRoles.HasChild ()
|
||||
) {
|
||||
//
|
||||
var roleClaim = context.User.Claims
|
||||
.FirstOrDefault (c => c.Type == JwtClaimTypes.Role);
|
||||
var isRolePassed = !roleClaim.IsNull () &&
|
||||
routeDescriptor.AllowedRoles
|
||||
.Any (role => role
|
||||
.ToNormalString () == roleClaim.Value
|
||||
.ToNormalString ());
|
||||
if (!isRolePassed) {
|
||||
ThrowNotAuthorizedException ();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
context.Response.StatusCode = (int) HttpStatusCode.Unauthorized;
|
||||
return;
|
||||
}
|
||||
#endregion
|
||||
|
||||
//
|
||||
// Extract Request Uri from Received Request ...
|
||||
var requestUri = GetUri (context.Request);
|
||||
if (!requestUri.IsNull ()) {
|
||||
//
|
||||
// Retrieve Request based on current ...
|
||||
var request = GetRequestMessage (
|
||||
uri: requestUri,
|
||||
context: context
|
||||
);
|
||||
|
||||
//
|
||||
SendLog ($"Send Request to Recieve Response ...", LogLevel.Information);
|
||||
|
||||
//
|
||||
// Send Request and Retrieve Response ...
|
||||
try {
|
||||
//
|
||||
var response = await HTTP_CLIENT.SendAsync (
|
||||
request,
|
||||
HttpCompletionOption.ResponseContentRead
|
||||
);
|
||||
|
||||
//
|
||||
// Set Current Response Status Code ...
|
||||
context.Response.StatusCode = (int) response.StatusCode;
|
||||
|
||||
//
|
||||
// Retrieve Response Headers and Set To Current Response ...
|
||||
HandleResponseHeaders (context, response);
|
||||
|
||||
//
|
||||
// Processing Response Content ...
|
||||
await ProcessResponseContent (context, response);
|
||||
} catch (Exception ex) {
|
||||
//
|
||||
LogMessage ($"Exception: {ex.Message}", LogLevel.Error);
|
||||
|
||||
//
|
||||
context.Response.StatusCode = (int) HttpStatusCode.BadRequest;
|
||||
}
|
||||
|
||||
//
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
//
|
||||
await NEXT_MIDDLEWARE (context);
|
||||
}
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Private ...
|
||||
/// <summary>
|
||||
/// Throw Required Exception ...
|
||||
/// </summary>
|
||||
private void ThrowNotAuthorizedException () {
|
||||
throw XException.NotAuthorized.ToException ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Show propper logs if Enabled ...
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="logLevel"></param>
|
||||
private void SendLog (string message, LogLevel logLevel = LogLevel.Information) {
|
||||
//
|
||||
if (!CONFIGURATION.EnableLogging) {
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
LogMessage (
|
||||
message: message,
|
||||
logLevel: logLevel
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Log Proxy Server Configuration ...
|
||||
/// </summary>
|
||||
private void LogXProxyServerConfig () {
|
||||
//
|
||||
// Retrieve XProxyConfiguration class from Configurations and Validate them ...
|
||||
if (CONFIGURATION.IsNull ()) {
|
||||
throw XException.InvalidConfiguration.ToException ();
|
||||
}
|
||||
|
||||
//
|
||||
// Try to Log Proxy Configuration ...
|
||||
ConsoleMessage ("===============================");
|
||||
ConsoleMessage ("= Proxy Server Configurations: ");
|
||||
ConsoleMessage ("===============================");
|
||||
|
||||
//
|
||||
ConsoleMessage ($"Host: {CONFIGURATION.Host}");
|
||||
ConsoleMessage ($"XPoweredValue: {CONFIGURATION.XPoweredValue}");
|
||||
ConsoleMessage ($"EnableLogging: {CONFIGURATION.EnableLogging}");
|
||||
ConsoleMessage ($"DisableSSLCheck: {CONFIGURATION.DisableSSLCheck}");
|
||||
ConsoleMessage ($"AllowAutoRedirect: {CONFIGURATION.AllowAutoRedirect}");
|
||||
ConsoleMessage ($" ");
|
||||
ConsoleMessage ($"Routes: ");
|
||||
ConsoleMessage ($" ");
|
||||
|
||||
//
|
||||
CONFIGURATION.Routes
|
||||
.ToList ()
|
||||
.ForEach (routeDescriptor => {
|
||||
ConsoleMessage ("===============================");
|
||||
ConsoleMessage ($"= Rote => {routeDescriptor.Route}");
|
||||
ConsoleMessage ("===============================");
|
||||
ConsoleMessage ($"AllowedRoles: {routeDescriptor.AllowedRoles.ToJSON()}");
|
||||
ConsoleMessage ($"AllowedScopes: {routeDescriptor.AllowedScopes.ToJSON()}");
|
||||
ConsoleMessage ($"EnableAuthorization: {routeDescriptor.EnableAuthorization}");
|
||||
ConsoleMessage ($"EnableXPoweredByAthorization: {routeDescriptor.EnableXPoweredByAthorization}");
|
||||
ConsoleMessage ($" ");
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve Destination Request Path based on Current Request ...
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
private Uri GetUri (HttpRequest request) {
|
||||
//
|
||||
// Create temp result ...
|
||||
Uri result = null;
|
||||
var requestPath = "";
|
||||
|
||||
//
|
||||
SendLog ($"Receive Request: {request.Path} ...", LogLevel.Information);
|
||||
|
||||
//
|
||||
// Try to Findout Route Descriptor ...
|
||||
var routeDescriptor = GetRouteDescriptor (request);
|
||||
|
||||
//
|
||||
// Route Descriptor Exists && Path for Delegating ...
|
||||
if (!routeDescriptor.IsNull () &&
|
||||
request.Path
|
||||
.StartsWithSegments (routeDescriptor.Route)
|
||||
) {
|
||||
//
|
||||
// Prepare Request Path by Cleaning Starter Path Segment ...
|
||||
requestPath = request.Path
|
||||
.ToString ()
|
||||
.Replace (routeDescriptor.Route, "");
|
||||
if (requestPath.StartsWith ("/")) {
|
||||
requestPath = requestPath.Substring (1);
|
||||
}
|
||||
|
||||
//
|
||||
// Decoding URL ...
|
||||
requestPath = HttpUtility.UrlDecode (requestPath);
|
||||
|
||||
//
|
||||
var colonIndex = requestPath.IndexOf (":");
|
||||
if (colonIndex > -1) {
|
||||
//
|
||||
var doubleSlash = requestPath.Substring (colonIndex + 1, 2);
|
||||
var isDoubleSlash = doubleSlash == "//";
|
||||
|
||||
//
|
||||
if (!isDoubleSlash) {
|
||||
//
|
||||
var protocol = requestPath
|
||||
.Substring (0, colonIndex);
|
||||
var section = requestPath
|
||||
.Substring (colonIndex + 2, requestPath.Length - colonIndex - 2);
|
||||
|
||||
//
|
||||
requestPath = $"{protocol}://{section}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Validate Request Path ...
|
||||
if (!requestPath.IsNullOrEmpty ()) {
|
||||
//
|
||||
result = new Uri (requestPath);
|
||||
|
||||
//
|
||||
SendLog ($"Process Request: {requestPath} ...", LogLevel.Information);
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve Propper Request Message based on HttpContext and uri ...F
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="uri"></param>
|
||||
/// <returns></returns>
|
||||
private HttpRequestMessage GetRequestMessage (
|
||||
HttpContext context,
|
||||
Uri uri
|
||||
) {
|
||||
//
|
||||
var result = new HttpRequestMessage ();
|
||||
FillRequest (context, result);
|
||||
|
||||
//
|
||||
// Handle Queries ...
|
||||
SendLog ($"Start Processing Queries: ");
|
||||
foreach (var query in context.Request.Query) {
|
||||
//
|
||||
var key = query.Key;
|
||||
var value = HttpUtility.UrlDecode (query.Value);
|
||||
|
||||
//
|
||||
uri = new Uri (
|
||||
QueryHelpers.AddQueryString (
|
||||
uri.OriginalString,
|
||||
new Dictionary<string, string> {
|
||||
[key] = value
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
//
|
||||
SendLog ($"Query : {key}:{value} was Processed ...");
|
||||
}
|
||||
|
||||
//
|
||||
result.RequestUri = uri;
|
||||
result.Headers.Host = uri.Host;
|
||||
|
||||
//
|
||||
// Retrieve Request Method ...
|
||||
result.Method = GetMethod (context.Request.Method);
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fill Request Message by provide HttpContext ...
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="message"></param>
|
||||
private void FillRequest (
|
||||
HttpContext context,
|
||||
HttpRequestMessage message
|
||||
) {
|
||||
//
|
||||
var requestMethod = context.Request.Method;
|
||||
|
||||
//
|
||||
if (!HttpMethods.IsGet (requestMethod) &&
|
||||
!HttpMethods.IsHead (requestMethod) &&
|
||||
!HttpMethods.IsTrace (requestMethod) &&
|
||||
!HttpMethods.IsDelete (requestMethod)
|
||||
) {
|
||||
//
|
||||
var streamContent = new StreamContent (context.Request.Body);
|
||||
message.Content = streamContent;
|
||||
}
|
||||
|
||||
//
|
||||
// Handle Base Headers ...
|
||||
var regularHeaders = context.Request.Headers
|
||||
.Where (hr => hr.Key != XProxyConstants.XPROXY_ACCEPTED_HEADERS &&
|
||||
!hr.Key
|
||||
.Contains (
|
||||
XProxyConstants.XPROXY_FORWARD_HEADER
|
||||
)
|
||||
);
|
||||
|
||||
//
|
||||
// Handle Aceepted Headers ...
|
||||
IEnumerable<string> acceptedHeaders = null;
|
||||
var acceptedHeadersKeyValue = context.Request.Headers
|
||||
.FirstOrDefault (hr =>
|
||||
hr.Key == XProxyConstants.XPROXY_ACCEPTED_HEADERS
|
||||
);
|
||||
if (!acceptedHeadersKeyValue.IsNull ()) {
|
||||
//
|
||||
acceptedHeaders = acceptedHeadersKeyValue.Value
|
||||
.ToString ()
|
||||
.ParseListString<string> ();
|
||||
|
||||
//
|
||||
// Filter Regular Headers ...
|
||||
if (
|
||||
regularHeaders.HasChild () &&
|
||||
acceptedHeaders.HasChild ()
|
||||
) {
|
||||
//
|
||||
regularHeaders = regularHeaders
|
||||
.Where (rhr => acceptedHeaders
|
||||
.Contains (rhr.Key)
|
||||
);
|
||||
}
|
||||
}
|
||||
foreach (var header in regularHeaders) {
|
||||
//
|
||||
SendLog ($"Adding Header: {header.Key}:{header.Value} ...");
|
||||
|
||||
//
|
||||
message.Headers.Add (
|
||||
header.Key,
|
||||
header.Value
|
||||
.ToString ()
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// Handle ForWarded Headers ...
|
||||
// Since Forward Headers is Custom kind, this means user actually need this
|
||||
// Header, so there is no need to put them on AcceptedHeaders ...
|
||||
var forwardHeaders = context.Request.Headers
|
||||
.Where (hr => hr.Key
|
||||
.Contains (
|
||||
XProxyConstants.XPROXY_FORWARD_HEADER
|
||||
)
|
||||
);
|
||||
foreach (var header in forwardHeaders) {
|
||||
//
|
||||
var key = header.Key
|
||||
.Replace (
|
||||
XProxyConstants.XPROXY_FORWARD_HEADER,
|
||||
string.Empty
|
||||
);
|
||||
|
||||
//
|
||||
SendLog ($"Forwarding Header: {header.Key} to {key} ...");
|
||||
|
||||
//
|
||||
message.Headers
|
||||
.Add (
|
||||
key,
|
||||
header.Value
|
||||
.ToString ()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retreive and Extract Method Type of HttpRequest ...
|
||||
/// </summary>
|
||||
/// <param name="method"></param>
|
||||
/// <returns></returns>
|
||||
private static HttpMethod GetMethod (string method) {
|
||||
//
|
||||
if (HttpMethods.IsDelete (method)) {
|
||||
return HttpMethod.Delete;
|
||||
} else if (HttpMethods.IsGet (method)) {
|
||||
return HttpMethod.Get;
|
||||
} else if (HttpMethods.IsHead (method)) {
|
||||
return HttpMethod.Head;
|
||||
} else if (HttpMethods.IsOptions (method)) {
|
||||
return HttpMethod.Options;
|
||||
} else if (HttpMethods.IsPost (method)) {
|
||||
return HttpMethod.Post;
|
||||
} else if (HttpMethods.IsPut (method)) {
|
||||
return HttpMethod.Put;
|
||||
} else if (HttpMethods.IsTrace (method)) {
|
||||
return HttpMethod.Trace;
|
||||
}
|
||||
|
||||
//
|
||||
return new HttpMethod (method);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// add all headers exists in HttpResponse MEssage to Current Context Response Headers ...
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="message"></param>
|
||||
private void HandleResponseHeaders (
|
||||
HttpContext context,
|
||||
HttpResponseMessage message
|
||||
) {
|
||||
//
|
||||
// Handle Message Headers ...
|
||||
foreach (var header in message.Headers) {
|
||||
context.Response.Headers[header.Key] = header.Value
|
||||
.ToArray ();
|
||||
}
|
||||
|
||||
//
|
||||
// Handle Message Content Headers ...
|
||||
foreach (var header in message.Content.Headers) {
|
||||
context.Response.Headers[header.Key] = header.Value
|
||||
.ToArray ();
|
||||
}
|
||||
|
||||
//
|
||||
context.Response.Headers.Remove ("transfer-encoding");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processing Response Content and Handle it on HttpContextResponse ...
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="response"></param>
|
||||
/// <returns></returns>
|
||||
private async Task ProcessResponseContent (
|
||||
HttpContext context,
|
||||
HttpResponseMessage message
|
||||
) {
|
||||
//
|
||||
// Reading Content as Byte Array ...
|
||||
var contentBytes = await message.Content
|
||||
.ReadAsByteArrayAsync ();
|
||||
|
||||
//
|
||||
// Check ContentType of Response ...
|
||||
if (
|
||||
IsContentOfType (message, XResponseContentTypes.HTML) ||
|
||||
IsContentOfType (message, XResponseContentTypes.JSON) ||
|
||||
IsContentOfType (message, XResponseContentTypes.JavaScript)
|
||||
) {
|
||||
//
|
||||
// If their String Content ...
|
||||
var stringContent = Encoding.UTF8.GetString (contentBytes);
|
||||
|
||||
//
|
||||
// TODO: here we can change String Contents ...
|
||||
|
||||
//
|
||||
// Writing new Content to Response ...
|
||||
await context.Response
|
||||
.WriteAsync (
|
||||
stringContent,
|
||||
Encoding.UTF8
|
||||
);
|
||||
} else {
|
||||
//
|
||||
// if they have non string content ...
|
||||
await context.Response.Body
|
||||
.WriteAsync (
|
||||
buffer: contentBytes,
|
||||
offset: 0,
|
||||
count: contentBytes.Length
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
SendLog ($"Response Content Processed ...", LogLevel.Information);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check Content Type of Specific Response ...
|
||||
/// </summary>
|
||||
/// <param name="response"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
private bool IsContentOfType (
|
||||
HttpResponseMessage response,
|
||||
string type
|
||||
) {
|
||||
//
|
||||
// Create EMpty Result ...
|
||||
var result = false;
|
||||
|
||||
//
|
||||
// Retrieve and Check Content Type of Response ...
|
||||
if (response.Content?.Headers?.ContentType != null) {
|
||||
result = response.Content.Headers.ContentType.MediaType == type;
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve and Extract Route Descriptor ...
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
private XProxyRouteDescriptor GetRouteDescriptor (HttpRequest request) {
|
||||
//
|
||||
// Validate Args ...
|
||||
if (
|
||||
CONFIGURATION.IsNull () ||
|
||||
!CONFIGURATION.Routes.HasChild ()
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
//
|
||||
var result = CONFIGURATION.Routes
|
||||
.FirstOrDefault (rd => !rd.Route.IsNullOrEmpty () &&
|
||||
request.Path
|
||||
.StartsWithSegments (rd.Route
|
||||
.ToNormalString ()
|
||||
)
|
||||
);
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provide all requirements for Dependency Injection Handler ...
|
||||
/// </summary>
|
||||
public static class XDIHelperExtension {
|
||||
/// <summary>
|
||||
/// Retrieve XProxy Middelware Configuration from Configuration ...
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
/// <returns></returns>
|
||||
public static XProxyConfiguration GetXProxyConfiguration (this IConfiguration config) {
|
||||
//
|
||||
var xProxyConfiguration = config.GetSection (ConfigurationNodeNames.XPROXY_CONFIGURATION_NODE_NAME);
|
||||
return xProxyConfiguration.Get<XProxyConfiguration> ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register HTTP Handler for XProxy Server ...
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
/// <param name="configuration"></param>
|
||||
/// <param name="httpHandler"></param>
|
||||
public static void AddXProxyHttpHandler (
|
||||
this IServiceCollection services,
|
||||
IConfiguration configuration,
|
||||
HttpClientHandler httpHandler = null
|
||||
) {
|
||||
//
|
||||
var proxyConfig = configuration.GetXProxyConfiguration ();
|
||||
if (proxyConfig.IsNull ()) {
|
||||
throw XException.InvalidConfiguration.ToException ();
|
||||
}
|
||||
|
||||
//
|
||||
services.AddXProxyHttpHandler (
|
||||
httpHandler: httpHandler,
|
||||
configuration: proxyConfig
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register HTTP Handler for XProxy Server ...
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
/// <param name="configuration"></param>
|
||||
/// <param name="httpHandler"></param>
|
||||
public static void AddXProxyHttpHandler (
|
||||
this IServiceCollection services,
|
||||
XProxyConfiguration configuration,
|
||||
HttpClientHandler httpHandler = null
|
||||
) {
|
||||
//
|
||||
if (configuration.IsNull ()) {
|
||||
throw XException.InvalidConfiguration.ToException ();
|
||||
}
|
||||
|
||||
//
|
||||
if (httpHandler.IsNull ()) {
|
||||
httpHandler = new HttpClientHandler ();
|
||||
}
|
||||
|
||||
//
|
||||
httpHandler.AllowAutoRedirect = configuration.AllowAutoRedirect;
|
||||
|
||||
//
|
||||
if (configuration.DisableSSLCheck) {
|
||||
httpHandler.ServerCertificateCustomValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true;
|
||||
}
|
||||
|
||||
//
|
||||
services
|
||||
.AddHttpClient (XProxyConstants.XPROXY_HTTP_CLIENT)
|
||||
.ConfigurePrimaryHttpMessageHandler (() => {
|
||||
return httpHandler;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register XProxy On Server ...
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
/// <param name="configuration"></param>
|
||||
/// <param name="httpHandler"></param>
|
||||
public static void AddXProxyServer (
|
||||
this IServiceCollection services,
|
||||
IConfiguration configuration,
|
||||
HttpClientHandler httpHandler = null
|
||||
) {
|
||||
//
|
||||
var proxyConfig = configuration.GetXProxyConfiguration ();
|
||||
|
||||
//
|
||||
services.AddXProxyServer (
|
||||
httpHandler: httpHandler,
|
||||
configuration: proxyConfig
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register XProxy On Server ...
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
/// <param name="configuration"></param>
|
||||
/// <param name="httpHandler"></param>
|
||||
public static void AddXProxyServer (
|
||||
this IServiceCollection services,
|
||||
XProxyConfiguration configuration,
|
||||
HttpClientHandler httpHandler = null
|
||||
) {
|
||||
//
|
||||
// Validate Args ...
|
||||
if (configuration.IsNull ()) {
|
||||
throw XException.InvalidConfiguration.ToException ();
|
||||
}
|
||||
|
||||
//
|
||||
// Register Proxy Configuration ...
|
||||
services.AddSingleton<XProxyConfiguration> (configuration);
|
||||
|
||||
//
|
||||
// Regiter Proxy Handler ...
|
||||
services.AddXProxyHttpHandler (
|
||||
httpHandler: httpHandler,
|
||||
configuration: configuration
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register XProxy On Server ...
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
/// <param name="configuration"></param>
|
||||
public static void AddXProxyClient (
|
||||
this IServiceCollection services,
|
||||
IConfiguration configuration
|
||||
) {
|
||||
//
|
||||
var proxyConfig = configuration.GetXProxyConfiguration ();
|
||||
|
||||
//
|
||||
services.AddXProxyClient (
|
||||
configuration: proxyConfig
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register XProxy On Client ...
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
/// <param name="configuration"></param>
|
||||
public static void AddXProxyClient (
|
||||
this IServiceCollection services,
|
||||
XProxyConfiguration configuration
|
||||
) {
|
||||
//
|
||||
// Validate Args ...
|
||||
if (configuration.IsNull ()) {
|
||||
throw XException.InvalidConfiguration.ToException ();
|
||||
}
|
||||
|
||||
//
|
||||
// Register Proxy Configuration ...
|
||||
services.AddSingleton<XProxyConfiguration> (configuration);
|
||||
|
||||
//
|
||||
// Register IXProxyHelper ...
|
||||
services.AddSingleton<IXProxyHelper, XProxyHelper> ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adding XProxy Middleware to Applications ...
|
||||
/// </summary>
|
||||
/// <param name="app"></param>
|
||||
public static void UseXProxy (this IApplicationBuilder app) {
|
||||
app.UseMiddleware<XProxyMiddleware> ();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user