119 lines
4.3 KiB
C#
119 lines
4.3 KiB
C#
using System;
|
|
using System.Linq;
|
|
using System.Net;
|
|
using Microsoft.AspNetCore.Antiforgery;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
|
|
namespace Microsoft.AspNetCore.Http
|
|
{
|
|
/// <summary>
|
|
/// Extensions for the <see cref="HttpContext"/>.
|
|
/// </summary>
|
|
public static class HttpContextExtensions
|
|
{
|
|
// Search these additional headers for a remote client ip address.
|
|
private static readonly string[] defaultIpHeaderNames = new[]
|
|
{
|
|
"Cf-Connecting-Ip", // set by Cloudflare
|
|
"X-Real-IP", // wide-spread alternative to X-Forwarded-For
|
|
"X-Forwarded-For", // commonly used on all known proxies
|
|
};
|
|
|
|
/// <summary>
|
|
/// Retrieves the antiforgery token.
|
|
/// </summary>
|
|
/// <param name="httpContext">The current <see cref="HttpContext"/>.</param>
|
|
/// <returns>FormName, HeaderName and Value of the antiforgery token.</returns>
|
|
public static (string FormName, string HeaderName, string Value) GetAntiforgeryToken(this HttpContext httpContext)
|
|
{
|
|
var antiforgery = httpContext.RequestServices.GetService<IAntiforgery>();
|
|
var tokenSet = antiforgery?.GetAndStoreTokens(httpContext);
|
|
|
|
return (tokenSet?.FormFieldName, tokenSet?.HeaderName, tokenSet?.RequestToken);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the remote ip address.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Searches for additional headers in the following order:
|
|
/// <list type="number">
|
|
/// <item>Cf-Connecting-Ip</item>
|
|
/// <item>X-Real-IP</item>
|
|
/// <item>X-Forwarded-For</item>
|
|
/// </list>
|
|
/// </remarks>
|
|
/// <param name="httpContext">The current <see cref="HttpContext"/>.</param>
|
|
/// <param name="ipHeaderName">The name of the header to resolve the <see cref="IPAddress"/> when behind a proxy.</param>
|
|
/// <returns>The ip address of the client.</returns>
|
|
public static IPAddress GetRemoteIpAddress(this HttpContext httpContext, string ipHeaderName = null)
|
|
{
|
|
string forwardedForAddress = null;
|
|
|
|
var headerNames = string.IsNullOrWhiteSpace(ipHeaderName)
|
|
? defaultIpHeaderNames
|
|
: new[] { ipHeaderName }.Concat(defaultIpHeaderNames);
|
|
foreach (string headerName in headerNames)
|
|
{
|
|
if (!httpContext.Request.Headers.ContainsKey(headerName))
|
|
continue;
|
|
|
|
// X-Forwarded-For can contain multiple comma-separated addresses.
|
|
forwardedForAddress = httpContext.Request.Headers[headerName].ToString()
|
|
.Split(',', StringSplitOptions.TrimEntries)
|
|
.First();
|
|
|
|
break;
|
|
}
|
|
|
|
if (!string.IsNullOrWhiteSpace(forwardedForAddress) && IPAddress.TryParse(forwardedForAddress, out var remoteAddress))
|
|
return remoteAddress.IsIPv4MappedToIPv6 ? remoteAddress.MapToIPv4() : remoteAddress;
|
|
|
|
return httpContext.Connection.RemoteIpAddress;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns whether the request was made locally.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Searches for additional headers in the following order:
|
|
/// <list type="number">
|
|
/// <item>Cf-Connecting-Ip</item>
|
|
/// <item>X-Real-IP</item>
|
|
/// <item>X-Forwarded-For</item>
|
|
/// </list>
|
|
/// </remarks>
|
|
/// <param name="httpContext">The current <see cref="HttpContext"/>.</param>
|
|
/// <param name="ipHeaderName">The name of the header to resolve the <see cref="IPAddress"/> when behind a proxy.</param>
|
|
/// <returns></returns>
|
|
public static bool IsLocalRequest(this HttpContext httpContext, string ipHeaderName = null)
|
|
{
|
|
var remoteIpAddress = httpContext.GetRemoteIpAddress(ipHeaderName);
|
|
return httpContext.Connection.LocalIpAddress.Equals(remoteIpAddress);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tries to retrieve the return url.
|
|
/// </summary>
|
|
/// <param name="httpContext">The current <see cref="HttpContext"/>.</param>
|
|
/// <returns></returns>
|
|
public static string GetReturnUrl(this HttpContext httpContext)
|
|
{
|
|
if (httpContext.Items.ContainsKey("OriginalRequest"))
|
|
return httpContext.Items["OriginalRequest"].ToString();
|
|
|
|
if (httpContext.Request.Query.ContainsKey("ReturnUrl"))
|
|
return httpContext.Request.Query["ReturnUrl"].ToString();
|
|
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clears a session when available.
|
|
/// </summary>
|
|
/// <param name="httpContext">The current <see cref="HttpContext"/>.</param>
|
|
public static void ClearSession(this HttpContext httpContext)
|
|
=> httpContext.Session?.Clear();
|
|
}
|
|
}
|