ASP.NET MVC'de istemcinin IP adresini nasıl alabilirim?


311

Ben tamamen ASP.NET MVC yığını için yeni ve basit Page nesnesi ve İstek ServerVariables nesnesine ne olduğunu merak ediyordum?

Temel olarak, istemci bilgisayarın IP adresini çıkarmak istiyorum, ancak geçerli MVC yapısının tüm bunları nasıl değiştirdiğini anlayamıyorum.

Anlayabildiğim kadarıyla, değişken nesnelerin çoğu HttpRequest varyantları ile değiştirildi .

Bazı kaynakları paylaşmak isteyen var mı? ASP.NET MVC dünyasında öğrenilecek çok şey var. :)

Örneğin, bu geçerli işlev ile statik bir sınıf var. ASP.NET MVC kullanarak aynı sonucu nasıl alabilirim?

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

Ve bu işlevi denetleyici sayfasından nasıl çağırırım?



Yanıtlar:


427

Basit cevap HttpRequest.UserHostAddress özelliğini kullanmaktır .

Örnek: Bir Denetleyici içinden:

using System;
using System.Web.Mvc;

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

            ...
        }
    }
}

Örnek: Bir yardımcı sınıfın içinden:

using System.Web;

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

Ancak, istek bir veya daha fazla proxy sunucusu tarafından iletildiyse, HttpRequest.UserHostAddress özelliği tarafından döndürülen IP adresi, isteği geçiren son proxy sunucusunun IP adresi olacaktır.

Proxy sunucular OLABİLİR kullanmak fiili müşterinin IP adresini yerleştirme standardını X-Forward-For HTTP başlık. Ayrıca, bir isteğin X-Forwarded-For üstbilgisine sahip olduğunun garantisi yoktur, X-Forwarded- For'ın SPOOFED olmadığının garantisi de yoktur .


Orijinal Yanıt

Request.UserHostAddress

Yukarıdaki kod, bir koleksiyona bakmadan Müşterinin IP adresini sağlar. Request özelliği Denetleyiciler (veya Görünümler) içinde kullanılabilir. Bu nedenle, işlevinize bir Page sınıfı iletmek yerine, aynı sonucu almak için bir Request nesnesi iletebilirsiniz:

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: Birden çok proxy sunucusu olabilir, çünkü birden çok proxy sunucusu istemcinin HTTP isteği boyunca yönlendirme yapıyor olabilir. Proxy sunucuları "iyi davranılmışsa" (kasıtlı olarak anonim proxy'lerin veya yalnızca kötü programlanmış sunucuların aksine), her biri XFF üstbilgisinde bir öncekinin IP'sine yapışır.
Eric J.9

14
İsPrivateIP yöntemi ne işe yarar?
eddiegroves

19
":: 1" localhost anlamına gelir. Sadece basit bir not.
tomg

5
X-Forwarded-For başlığı, paketleri analiz eden ve ortada bir adam gibi davranan güvenlik duvarları ve yük dengeleyiciler tarafından eklenir. Orijinal kullanıcının ip adresini korumak için, bu bilgi orijinal bilgilerin alınabilmesi için eklenir. Paket yeniden yazıldığında, yeni ip adresi genellikle dahili bir iptir ve çok yararlı değildir.
Marko

2
Teşekkür ederim, bu bana yardımcı oldu.
Jack Fairfield

168

Request.ServerVariables["REMOTE_ADDR"] doğrudan bir görünümde veya denetleyici eylem yöntemi gövdesinde çalışmalıdır (İstek MVC'de Denetleyici sınıfının bir özelliğidir, Sayfa değil).

Çalışıyor .. ama sanal bir değil gerçek bir IIS üzerinde yayınlamak zorunda.


bunu kontrolör tarafından nasıl arayabilirim?
melaos

lol, hey işe yarıyor, yukarıdaki gibi bir sınıf nesnesine koymak istersem ne olur? ve hala sayfa nesnesine ihtiyacım var mı?
melaos

11
Ben HttpContext.Current.Request kullanabilirsiniz düşünüyorum
ovolko

23
Adrian'ın cevabı (aşağıda) çok daha iyi - sihirli dize ile bir arama yapmaya gerek yok. Request.UserHostAddress kullanın
csauve

Bu her zaman uygulamamı çalıştıran sunucunun IP adresini döndürür. Neden?
Jack Marchetti

101

Buradaki kodun birçoğu çok yardımcı oldu, ancak amaçlarım için temizledim ve bazı testler ekledim. İşte sonuçta:

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

Ve bu koda karşı bazı NUnit testleri (aşağıda M <HttpRequestBase> çağrısı olan HttpRequestBase, alay için Rhino Mocks kullanıyorum):

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
Bu her zaman uygulamamı çalıştıran sunucunun IP adresini döndürür.
Jack Marchetti

1
Geri dönmemeli publicForwardingIps.First()mi?
andy250

1
@ Hayır, IPv6 adresleri için işe yaramayacağını tahmin ediyorum.
AidanO

Güzel çözüm! IPAddress.Parse () diğer IP adreslerinde de kullanılmalı mıdır?
Co-der

21

Yukarıdakileri kullanırken sorun yaşadım ve bir denetleyiciden IP adresine ihtiyacım vardı. Sonunda aşağıdakileri kullandım:

System.Web.HttpContext.Current.Request.UserHostAddress

2
Denetleyiciden tek yapmanız gerekenHttpContext.Request.UserHostAddress
Serj Sagan

Teşekkürler. Bu bir denetleyici veya bir görünüm bağlamında değil bir yardımcı sınıfta ne gerek. Bu güzel bir evrensel cevap. +1
Piotr Kula

@gander Ne demek istiyorsun? Açıklamayı kim yazmalıyım?
Piotr Kula

1
Yardımcı sınıfın en üstüne "using System.Web;" yazmanız yeterlidir, o zaman yalnızca "HttpContext.Current.Request.UserHostAddress" yazmanız gerekir. Sadece tembel programcılar için, benim gibi (ve Tom'un cevabının ve
Serj'in

19

Bir sınıfta şöyle diyebilirsiniz:

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

Bunu harika sonuçlarla bir jilet uygulamasında kullandım.


Son adresi neden HTTP_X_FORWARDED_FOR adresinden döndürüyorsunuz? İlk adres değil müşteri adresi mi?
Igor Yalovoy

1

Sitemin Amazon AWS Elastik Yük Dengeleyicisinin (ELB) arkasında olduğunu nasıl açıklarım:

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;
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.