Wie kann ich die IP-Adresse des Clients in ASP.NET MVC abrufen?

311

Ich bin völlig neu im ASP.NET MVC-Stack und habe mich gefragt, was mit dem einfachen Page-Objekt und dem Request ServerVariables-Objekt passiert ist.

Grundsätzlich möchte ich die IP-Adresse des Client-PCs abrufen, aber ich verstehe nicht, wie die aktuelle MVC-Struktur all dies geändert hat.

Soweit ich verstehen kann, wurden die meisten variablen Objekte durch die HttpRequest-Varianten ersetzt .

Möchte jemand Ressourcen teilen? In der ASP.NET MVC-Welt gibt es wirklich viel zu lernen. :) :)

Zum Beispiel habe ich eine statische Klasse mit dieser aktuellen Funktion. Wie erhalte ich mit ASP.NET MVC das gleiche Ergebnis?

public static int getCountry(Page page)
{
    return getCountryFromIP(getIPAddress(page));
}

public static string getIPAddress(Page page)
{
    string szRemoteAddr = page.Request.ServerVariables["REMOTE_ADDR"];
    string szXForwardedFor = page.Request.ServerVariables["X_FORWARDED_FOR"];
    string szIP = "";

    if (szXForwardedFor == null)
    {
        szIP = szRemoteAddr;
    }
    else
    {
        szIP = szXForwardedFor;

        if (szIP.IndexOf(",") > 0)
        {
            string [] arIPs = szIP.Split(',');

            foreach (string item in arIPs)
            {
                if (!isPrivateIP(item))
                {
                    return item;
                }
            }
        }
    }
    return szIP;
}

Und wie rufe ich diese Funktion von der Controller-Seite auf?

melaos
quelle

Antworten:

427

Die einfache Antwort besteht darin, die Eigenschaft HttpRequest.UserHostAddress zu verwenden .

Beispiel: Innerhalb eines Controllers:

using System;
using System.Web.Mvc;

namespace Mvc.Controllers
{
    public class HomeController : ClientController
    {
        public ActionResult Index()
        {
            string ip = Request.UserHostAddress;

            ...
        }
    }
}

Beispiel: Aus einer Hilfsklasse heraus:

using System.Web;

namespace Mvc.Helpers
{
    public static class HelperClass
    {
        public static string GetIPHelper()
        {
            string ip = HttpContext.Current.Request.UserHostAddress;
            ..
        }
    }
}

ABER wenn die Anforderung von einem oder mehreren Proxyservern weitergeleitet wurde, ist die von der Eigenschaft HttpRequest.UserHostAddress zurückgegebene IP-Adresse die IP-Adresse des letzten Proxyservers, der die Anforderung weitergeleitet hat.

Proxyserver KÖNNEN den De-facto- Standard verwenden, die IP-Adresse des Clients in den HTTP-Header X-Forwarded-For aufzunehmen . Abgesehen davon, dass es keine Garantie dafür gibt, dass eine Anfrage einen X-Forwarded-For-Header hat, gibt es auch keine Garantie dafür, dass das X-Forwarded-For nicht SPOOFED wurde .


Ursprüngliche Antwort

Request.UserHostAddress

Der obige Code gibt die IP-Adresse des Kunden an, ohne eine Sammlung nachschlagen zu müssen. Die Request-Eigenschaft ist in Controllern (oder Ansichten) verfügbar. Anstatt eine Page-Klasse an Ihre Funktion zu übergeben, können Sie daher ein Request-Objekt übergeben, um dasselbe Ergebnis zu erhalten:

public static string getIPAddress(HttpRequestBase request)
{
    string szRemoteAddr = request.UserHostAddress;
    string szXForwardedFor = request.ServerVariables["X_FORWARDED_FOR"];
    string szIP = "";

    if (szXForwardedFor == null)
    {
        szIP = szRemoteAddr;
    }
    else
    {
        szIP = szXForwardedFor;
        if (szIP.IndexOf(",") > 0)
        {
            string [] arIPs = szIP.Split(',');

            foreach (string item in arIPs)
            {
                if (!isPrivateIP(item))
                {
                    return item;
                }
            }
        }
    }
    return szIP;
}
Adrian Toman
quelle
6
@ makerofthings7: Es können mehrere Werte vorhanden sein, da möglicherweise mehrere Proxyserver entlang der HTTP-Anforderung des Clients weitergeleitet werden. Wenn sich die Proxyserver "gut benehmen" (im Gegensatz zu absichtlich anonymen oder nur schlecht programmierten Proxys), greift jeder die IP des vorherigen im XFF-Header an.
Eric J.
14
Was macht die isPrivateIP-Methode?
Eddiegroves
19
":: 1" bedeutet localhost. Nur eine einfache Anmerkung.
Tomg
5
Der X-Forwarded-For-Header wird von Firewalls und Load Balancern hinzugefügt, die Pakete analysieren und als Mann in der Mitte fungieren. Um die IP-Adresse des ursprünglichen Benutzers beizubehalten, wird dieser Header hinzugefügt, damit die ursprünglichen Informationen abgerufen werden können. Wenn das Paket neu geschrieben wird, ist die neue IP-Adresse normalerweise eine interne IP und nicht sehr nützlich.
Marko
2
Danke, das hat mir geholfen.
Jack Fairfield
168

Request.ServerVariables["REMOTE_ADDR"] sollte funktionieren - entweder direkt in einer Ansicht oder im Hauptteil der Controller-Aktionsmethode (Request ist eine Eigenschaft der Controller-Klasse in MVC, nicht Page).

Es funktioniert .. aber Sie müssen auf einem realen IIS veröffentlichen, nicht auf dem virtuellen.

ovolko
quelle
Wie nenne ich das von der Controllerseite?
Melaos
lol, hey das funktioniert, was passiert, wenn ich das wie oben in ein Klassenobjekt einfügen möchte? und brauche ich noch das seitenobjekt?
Melaos
11
Ich denke, Sie könnten HttpContext.Current.Request
ovolko
23
Die Antwort von Adrian (unten) ist viel besser - es muss nicht nach einer magischen Schnur gesucht werden. Verwenden Sie Request.UserHostAddress
csauve
Dies gibt immer die IP-Adresse des Servers zurück, auf dem meine App ausgeführt wird. Irgendein Grund warum?
Jack Marchetti
101

Ein Großteil des Codes hier war sehr hilfreich, aber ich habe ihn für meine Zwecke aufgeräumt und einige Tests hinzugefügt. Folgendes habe ich erreicht:

using System;
using System.Linq;
using System.Net;
using System.Web;

public class RequestHelpers
{
    public static string GetClientIpAddress(HttpRequestBase request)
    {
        try
        {
            var userHostAddress = request.UserHostAddress;

            // Attempt to parse.  If it fails, we catch below and return "0.0.0.0"
            // Could use TryParse instead, but I wanted to catch all exceptions
            IPAddress.Parse(userHostAddress);

            var xForwardedFor = request.ServerVariables["X_FORWARDED_FOR"];

            if (string.IsNullOrEmpty(xForwardedFor))
                return userHostAddress;

            // Get a list of public ip addresses in the X_FORWARDED_FOR variable
            var publicForwardingIps = xForwardedFor.Split(',').Where(ip => !IsPrivateIpAddress(ip)).ToList();

            // If we found any, return the last one, otherwise return the user host address
            return publicForwardingIps.Any() ? publicForwardingIps.Last() : userHostAddress;
        }
        catch (Exception)
        {
            // Always return all zeroes for any failure (my calling code expects it)
            return "0.0.0.0";
        }
    }

    private static bool IsPrivateIpAddress(string ipAddress)
    {
        // http://en.wikipedia.org/wiki/Private_network
        // Private IP Addresses are: 
        //  24-bit block: 10.0.0.0 through 10.255.255.255
        //  20-bit block: 172.16.0.0 through 172.31.255.255
        //  16-bit block: 192.168.0.0 through 192.168.255.255
        //  Link-local addresses: 169.254.0.0 through 169.254.255.255 (http://en.wikipedia.org/wiki/Link-local_address)

        var ip = IPAddress.Parse(ipAddress);
        var octets = ip.GetAddressBytes();

        var is24BitBlock = octets[0] == 10;
        if (is24BitBlock) return true; // Return to prevent further processing

        var is20BitBlock = octets[0] == 172 && octets[1] >= 16 && octets[1] <= 31;
        if (is20BitBlock) return true; // Return to prevent further processing

        var is16BitBlock = octets[0] == 192 && octets[1] == 168;
        if (is16BitBlock) return true; // Return to prevent further processing

        var isLinkLocalAddress = octets[0] == 169 && octets[1] == 254;
        return isLinkLocalAddress;
    }
}

Und hier sind einige NUnit-Tests für diesen Code (ich verwende Rhino Mocks, um die HttpRequestBase zu verspotten, die der M <HttpRequestBase> -Aufruf unten ist):

using System.Web;
using NUnit.Framework;
using Rhino.Mocks;
using Should;

[TestFixture]
public class HelpersTests : TestBase
{
    HttpRequestBase _httpRequest;

    private const string XForwardedFor = "X_FORWARDED_FOR";
    private const string MalformedIpAddress = "MALFORMED";
    private const string DefaultIpAddress = "0.0.0.0";
    private const string GoogleIpAddress = "74.125.224.224";
    private const string MicrosoftIpAddress = "65.55.58.201";
    private const string Private24Bit = "10.0.0.0";
    private const string Private20Bit = "172.16.0.0";
    private const string Private16Bit = "192.168.0.0";
    private const string PrivateLinkLocal = "169.254.0.0";

    [SetUp]
    public void Setup()
    {
        _httpRequest = M<HttpRequestBase>();
    }

    [TearDown]
    public void Teardown()
    {
        _httpRequest = null;
    }

    [Test]
    public void PublicIpAndNullXForwardedFor_Returns_CorrectIp()
    {
        // Arrange
        _httpRequest.Stub(x => x.UserHostAddress).Return(GoogleIpAddress);
        _httpRequest.Stub(x => x.ServerVariables[XForwardedFor]).Return(null);

        // Act
        var ip = RequestHelpers.GetClientIpAddress(_httpRequest);

        // Assert
        ip.ShouldEqual(GoogleIpAddress);
    }

    [Test]
    public void PublicIpAndEmptyXForwardedFor_Returns_CorrectIp()
    {
        // Arrange
        _httpRequest.Stub(x => x.UserHostAddress).Return(GoogleIpAddress);
        _httpRequest.Stub(x => x.ServerVariables[XForwardedFor]).Return(string.Empty);

        // Act
        var ip = RequestHelpers.GetClientIpAddress(_httpRequest);

        // Assert
        ip.ShouldEqual(GoogleIpAddress);
    }

    [Test]
    public void MalformedUserHostAddress_Returns_DefaultIpAddress()
    {
        // Arrange
        _httpRequest.Stub(x => x.UserHostAddress).Return(MalformedIpAddress);
        _httpRequest.Stub(x => x.ServerVariables[XForwardedFor]).Return(null);

        // Act
        var ip = RequestHelpers.GetClientIpAddress(_httpRequest);

        // Assert
        ip.ShouldEqual(DefaultIpAddress);
    }

    [Test]
    public void MalformedXForwardedFor_Returns_DefaultIpAddress()
    {
        // Arrange
        _httpRequest.Stub(x => x.UserHostAddress).Return(GoogleIpAddress);
        _httpRequest.Stub(x => x.ServerVariables[XForwardedFor]).Return(MalformedIpAddress);

        // Act
        var ip = RequestHelpers.GetClientIpAddress(_httpRequest);

        // Assert
        ip.ShouldEqual(DefaultIpAddress);
    }

    [Test]
    public void SingleValidPublicXForwardedFor_Returns_XForwardedFor()
    {
        // Arrange
        _httpRequest.Stub(x => x.UserHostAddress).Return(GoogleIpAddress);
        _httpRequest.Stub(x => x.ServerVariables[XForwardedFor]).Return(MicrosoftIpAddress);

        // Act
        var ip = RequestHelpers.GetClientIpAddress(_httpRequest);

        // Assert
        ip.ShouldEqual(MicrosoftIpAddress);
    }

    [Test]
    public void MultipleValidPublicXForwardedFor_Returns_LastXForwardedFor()
    {
        // Arrange
        _httpRequest.Stub(x => x.UserHostAddress).Return(GoogleIpAddress);
        _httpRequest.Stub(x => x.ServerVariables[XForwardedFor]).Return(GoogleIpAddress + "," + MicrosoftIpAddress);

        // Act
        var ip = RequestHelpers.GetClientIpAddress(_httpRequest);

        // Assert
        ip.ShouldEqual(MicrosoftIpAddress);
    }

    [Test]
    public void SinglePrivateXForwardedFor_Returns_UserHostAddress()
    {
        // Arrange
        _httpRequest.Stub(x => x.UserHostAddress).Return(GoogleIpAddress);
        _httpRequest.Stub(x => x.ServerVariables[XForwardedFor]).Return(Private24Bit);

        // Act
        var ip = RequestHelpers.GetClientIpAddress(_httpRequest);

        // Assert
        ip.ShouldEqual(GoogleIpAddress);
    }

    [Test]
    public void MultiplePrivateXForwardedFor_Returns_UserHostAddress()
    {
        // Arrange
        _httpRequest.Stub(x => x.UserHostAddress).Return(GoogleIpAddress);
        const string privateIpList = Private24Bit + "," + Private20Bit + "," + Private16Bit + "," + PrivateLinkLocal;
        _httpRequest.Stub(x => x.ServerVariables[XForwardedFor]).Return(privateIpList);

        // Act
        var ip = RequestHelpers.GetClientIpAddress(_httpRequest);

        // Assert
        ip.ShouldEqual(GoogleIpAddress);
    }

    [Test]
    public void MultiplePublicXForwardedForWithPrivateLast_Returns_LastPublic()
    {
        // Arrange
        _httpRequest.Stub(x => x.UserHostAddress).Return(GoogleIpAddress);
        const string privateIpList = Private24Bit + "," + Private20Bit + "," + MicrosoftIpAddress + "," + PrivateLinkLocal;
        _httpRequest.Stub(x => x.ServerVariables[XForwardedFor]).Return(privateIpList);

        // Act
        var ip = RequestHelpers.GetClientIpAddress(_httpRequest);

        // Assert
        ip.ShouldEqual(MicrosoftIpAddress);
    }
}
Noah Heldman
quelle
2
Dies gibt immer die IP-Adresse des Servers zurück, auf dem meine Anwendung ausgeführt wird.
Jack Marchetti
1
Sollte es das nicht zurückgeben publicForwardingIps.First()?
andy250
1
@Noah Ich vermute, das funktioniert nicht für IPv6-Adressen?
AidanO
Schöne Lösung! Sollte IPAddress.Parse () auch für die anderen IP-Adressen verwendet werden?
Co-der
21

Ich hatte Probleme mit der Verwendung der oben genannten Informationen und benötigte die IP-Adresse eines Controllers. Am Ende habe ich folgendes verwendet:

System.Web.HttpContext.Current.Request.UserHostAddress
Tom
quelle
2
Von der Steuerung war alles, was Sie tun musstenHttpContext.Request.UserHostAddress
Serj Sagan
Vielen Dank. Das, was ich in einer Hilfsklasse brauchte, nicht in einem Controller oder in einem Ansichtskontext. Dies ist eine schöne universelle Antwort. +1
Piotr Kula
@gander Was meinst du? Wie soll ich die Erklärung schreiben?
Piotr Kula
1
Schreiben Sie oben in der Hilfsklasse einfach "using System.Web;", dann müssen Sie nur noch "HttpContext.Current.Request.UserHostAddress" schreiben. Nur für die faulen Programmierer, wie ich (und erklärt, warum Toms Antwort und
Serjs
19

In einer Klasse könnte man es so nennen:

public static string GetIPAddress(HttpRequestBase request) 
{
    string ip;
    try
    {
        ip = request.ServerVariables["HTTP_X_FORWARDED_FOR"];
        if (!string.IsNullOrEmpty(ip))
        {
            if (ip.IndexOf(",") > 0)
            {
                string[] ipRange = ip.Split(',');
                int le = ipRange.Length - 1;
                ip = ipRange[le];
            }
        } else
        {
            ip = request.UserHostAddress;
        }
    } catch { ip = null; }

    return ip; 
}

Ich habe dies in einer Rasiermesser-App mit großartigen Ergebnissen verwendet.

Paul Keefe
quelle
Warum geben Sie die letzte Adresse von HTTP_X_FORWARDED_FOR zurück? Ist es die Kundenadresse, nicht die erste?
Igor Yalovoy
1

Wie kann ich erklären, dass meine Website hinter einem Amazon AWS Elastic Load Balancer (ELB) steht:

public class GetPublicIp {

    /// <summary>
    /// account for possbility of ELB sheilding the public IP address
    /// </summary>
    /// <returns></returns>
    public static string Execute() {
        try {
            Console.WriteLine(string.Join("|", new List<object> {
                    HttpContext.Current.Request.UserHostAddress,
                    HttpContext.Current.Request.Headers["X-Forwarded-For"],
                    HttpContext.Current.Request.Headers["REMOTE_ADDR"]
                })
            );

            var ip = HttpContext.Current.Request.UserHostAddress;
            if (HttpContext.Current.Request.Headers["X-Forwarded-For"] != null) {
                ip = HttpContext.Current.Request.Headers["X-Forwarded-For"];
                Console.WriteLine(ip + "|X-Forwarded-For");
            }
            else if (HttpContext.Current.Request.Headers["REMOTE_ADDR"] != null) {
                ip = HttpContext.Current.Request.Headers["REMOTE_ADDR"];
                Console.WriteLine(ip + "|REMOTE_ADDR");
            }
            return ip;
        }
        catch (Exception ex) {
            Console.Error.WriteLine(ex.Message);
        }
        return null;
    }
}
sobelito
quelle