Come posso ottenere l'indirizzo IP del client in ASP.NET MVC?


311

Sono totalmente nuovo nello stack ASP.NET MVC e mi chiedevo cosa è successo al semplice oggetto Page e all'oggetto Request ServerVariables?

Fondamentalmente, voglio estrarre l'indirizzo IP del PC client, ma non riesco a capire come l'attuale struttura MVC abbia cambiato tutto questo.

Per quanto posso capire, la maggior parte degli oggetti variabili è stata sostituita dalle varianti di HttpRequest .

Qualcuno ha voglia di condividere alcune risorse? C'è davvero un mare di cose da imparare nel mondo ASP.NET MVC. :)

Ad esempio, ho una classe statica con questa funzione corrente. Come posso ottenere lo stesso risultato usando ASP.NET MVC?

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;
}

E come posso chiamare questa funzione dalla pagina del controller?



Risposte:


427

La semplice risposta è utilizzare la proprietà HttpRequest.UserHostAddress .

Esempio: dall'interno di un controller:

using System;
using System.Web.Mvc;

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

            ...
        }
    }
}

Esempio: dall'interno di una classe di supporto:

using System.Web;

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

MA, se la richiesta è stata trasmessa da uno o più server proxy , l'indirizzo IP restituito dalla proprietà HttpRequest.UserHostAddress sarà l'indirizzo IP dell'ultimo server proxy che ha inoltrato la richiesta.

I server proxy MAGGIO utilizzare il de facto standard ponendo l'indirizzo IP del client nel X-Forwarded-For header HTTP. A parte questo, non vi è alcuna garanzia che una richiesta abbia un'intestazione X-Forwarded-For, non esiste alcuna garanzia che X-Forwarded-For non sia stato SPOOFED .


Risposta originale

Request.UserHostAddress

Il codice sopra riportato fornisce l'indirizzo IP del Cliente senza ricorrere alla ricerca di una raccolta. La proprietà Request è disponibile in Controller (o Visualizzazioni). Pertanto, invece di passare una classe Page alla tua funzione, puoi passare un oggetto Request per ottenere lo stesso risultato:

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;
}

6
@ makerofthings7: possono esserci più valori perché più server proxy potrebbero essere inoltrati lungo la richiesta HTTP del client. Se i server proxy sono "ben educati" (al contrario di proxy intenzionalmente anonimi o semplicemente mal programmati), ognuno controllerà l'IP del precedente nell'intestazione XFF.
Eric J.

14
Cosa fa il metodo isPrivateIP?
Eddiegroves

19
":: 1" significa localhost. Solo una semplice nota.
tomg

5
L'intestazione X-Forwarded-For viene aggiunta dai firewall e dai bilanciatori del carico che analizzano i pacchetti e agiscono come un uomo nel mezzo. Per preservare l'indirizzo IP dell'utente originale, questa intestazione viene aggiunta in modo da poter recuperare le informazioni originali. Quando il pacchetto viene riscritto, il nuovo indirizzo IP è di solito un IP interno e non molto utile.
Marko,

2
Grazie, questo mi ha aiutato.
Jack Fairfield,

168

Request.ServerVariables["REMOTE_ADDR"] dovrebbe funzionare - direttamente in una vista o nel corpo del metodo di azione del controller (Request è una proprietà della classe Controller in MVC, non Pagina).

Funziona .. ma devi pubblicare su un vero IIS non quello virtuale.


come lo chiamo dal lato controller?
Melaos,

lol, ehi che funziona, cosa succede se desidero inserirlo in un oggetto di classe come sopra? e ho ancora bisogno dell'oggetto pagina?
melaos,

11
Penso che potresti usare HttpContext.Current.Request
ovolko

23
La risposta di Adrian (sotto) è molto migliore: non è necessario cercare una stringa magica. Usa Request.UserHostAddress
csauve

Questo restituisce sempre l'indirizzo IP del server che esegue la mia app. Qualche ragione per cui?
Jack Marchetti,

101

Molto del codice qui è stato molto utile, ma l'ho ripulito per i miei scopi e ho aggiunto alcuni test. Ecco cosa ho finito con:

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;
    }
}

E qui ci sono alcuni test NUnit contro quel codice (sto usando Rhino Mock per deridere HttpRequestBase, che è la chiamata M <HttpRequestBase> di seguito):

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);
    }
}

2
Ciò restituisce sempre l'indirizzo IP del server che esegue la mia applicazione.
Jack Marchetti,

1
Non dovrebbe restituire il publicForwardingIps.First()?
andy250,

1
@Noah Suppongo che non funzionerà per gli indirizzi IPv6?
AidanO

Bella soluzione! IPAddress.Parse () dovrebbe essere utilizzato anche sugli altri indirizzi IP?
Co-der

21

Ho avuto problemi con l'utilizzo di quanto sopra e avevo bisogno dell'indirizzo IP da un controller. Alla fine ho usato quanto segue:

System.Web.HttpContext.Current.Request.UserHostAddress

2
Dal controller tutto ciò che dovevi fare eraHttpContext.Request.UserHostAddress
Serj Sagan il

Grazie. Ciò di cui avevo bisogno in una classe di supporto non in un controller o in un contesto di vista. Questa è una bella risposta universale. +1
Piotr Kula,

@gander Cosa vuoi dire? Ho dovrei scrivere la dichiarazione?
Piotr Kula,

1
Nella parte superiore della classe helper, basta scrivere "using System.Web;", quindi devi solo scrivere "HttpContext.Current.Request.UserHostAddress". Solo per i programmatori pigri, come me (e spiega perché la risposta di Tom e il commento di Serj)
Ganders

19

In una classe potresti chiamarlo così:

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; 
}

L'ho usato in un'app per rasoio con grandi risultati.


Perché restituisci l'ultimo indirizzo da HTTP_X_FORWARDED_FOR? L'indirizzo del cliente non è il primo?
Igor Yalovoy,

1

Come conto del fatto che il mio sito sia protetto da un ELB (Elastic Load Balancer) Amazon AWS :

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;
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.