HttpListener Erişimi Reddedildi


180

C # 'da bir HTTP sunucusu yazıyorum.

İşlevi yürütmeye çalıştığımda HttpListener.Start()bir HttpListenerExceptionsöz alıyorum

"Erişim reddedildi".

Uygulamayı Windows 7'de yönetici modunda çalıştırdığımda iyi çalışıyor.

Yönetici modu olmadan çalıştırabilir miyim? evet ise nasıl? Değilse, çalışmaya başladıktan sonra uygulamanın yönetici moduna nasıl geçmesini sağlayabilirim?

using System;
using System.Net;

namespace ConsoleApplication1
{
    class Program
    {
        private HttpListener httpListener = null;

        static void Main(string[] args)
        {
            Program p = new Program();
            p.Server();
        }

        public void Server()
        {
            this.httpListener = new HttpListener();

            if (httpListener.IsListening)
                throw new InvalidOperationException("Server is currently running.");

            httpListener.Prefixes.Clear();
            httpListener.Prefixes.Add("http://*:4444/");

            try
            {
                httpListener.Start(); //Throws Exception
            }
            catch (HttpListenerException ex)
            {
                if (ex.Message.Contains("Access is denied"))
                {
                    return;
                }
                else
                {
                    throw;
                }
            }
        }
    }
}

Birisi bu hatayı önlemek istiyorsa, TcpListener ile yazmayı deneyebilir. Yönetici ayrıcalıkları gerektirmez
Vlad

Aynı sorunla karşılaşıyorum, Visual Studio 2008 + Windows 7'de, 'Erişim reddedildi' hatası üretiyor, bunu çözmek için Visual Studio 2008'i Yönetici Modunda çalıştırmak
Mark Khor

Yanıtlar:


307

Evet, HttpListener'ı yönetici olmayan modda çalıştırabilirsiniz. Tek yapmanız gereken, belirli bir URL'ye izin vermektir. Örneğin

netsh http add urlacl url=http://+:80/MyUri user=DOMAIN\user

Belgeler burada .


48
Bu yararlıdır, ancak eksiksiz olması için bu kod satırında belirtilen URL: httpListener.Prefixes.Add("http://*:4444/");TAM ile Komuttaki URL ile eşleşmelidir netsh. Örneğin, sahip olduğum komutla httpListener.Prefixes.Add("http://127.0.0.1:80/");aynı netshkomut aldım ve HttpListenerException yine de atılacak. Değiştirmem gerekiyor httpListener.Prefixes.Add("http://+:80/");Yardımın için teşekkürlerDarrel Miller, çünkü bunu çözmenin doğru yolunu buldun!
psyklopz

10
Ve "MyUri" boşsa sondaki eğik çizgiyi unutmayın, aksi takdirde bir The parameter is incorrecthata alırsınız . Örnek:url=http://+:80/
Igor Brejc

14
Bunu yönetici olmayan bir kullanıcı için bile yapmanın bir yolu var mı http://localhost:80/? Böyle bir URL üzerinde bir istek alması gereken bir masaüstü uygulamam var ve bir yöneticinin sadece bu amaçla 50 masaüstüne yüklemesini istemek utanç verici görünüyor.
John Saunders

5
Görünüşe göre öyle değil. Ayrıca, belge sayfasında yükseklik veya yönetici ayrıcalıklarına gerek yoktur. Bu yüzden, gerçekte kullanmamanın önemli bir nedeni olduğunda bunun "daha akıllı" bir TCPListener olarak görev yapacağını varsaymak kolaydır - ancak bu belgelenmemiştir.
David Ford

4
Netsh çalıştırmak yönetici gerektirir; (
superfly71

27

Yönetici modu olmadan çalıştırabilir miyim? evet ise nasıl? Değilse, çalışmaya başladıktan sonra uygulamanın yönetici moduna nasıl geçmesini sağlayabilirim?

Yapamazsınız, yükseltilmiş ayrıcalıklarla başlamak zorunda. runasKullanıcıdan yönetici moduna geçmesini isteyen fiil ile yeniden başlatabilirsiniz.

static void RestartAsAdmin()
{
    var startInfo = new ProcessStartInfo("yourApp.exe") { Verb = "runas" };
    Process.Start(startInfo);
    Environment.Exit(0);
}

EDIT: aslında, bu doğru değil; HttpListener yükseltilmiş ayrıcalıklar olmadan çalışabilir, ancak dinlemek istediğiniz URL için izin vermeniz gerekir. Ayrıntılar için Darrel Miller'ın cevabına bakınız.


Neden yükseltilmiş ayrıcalıklarla başlamak zorunda olduğumu açıklayabilir misiniz?
Randall Flagg

Ayrıca bu satırı 'startInfo.UseShellExecute = false;' önce 'Process.Start (startInfo);'
Randall Flagg

@Randall: çünkü Windows böyle çalışır ... bir işlem çalışırken yönetici moduna geçemez. UseShellExecute ile ilgili olarak: ne yürüttüğünüze bağlıdır. Kodumu "notepad.exe" ile test ettim, UseShellExecute = false olmadan iyi çalışıyor
Thomas Levesque

Teşekkürler. UseShellExecute Hakkında: Ben gönderdiğim kodu çalıştırmayı denedim. Başka bir sorun, bir nedenden dolayı bana yönetici olarak çalıştırmak isteyip istemediğimi bir kez sordu ve bundan sonra sormuyor. Yeniden başladım, oraya gittiğinden emin olmak için hata ayıkladım. baska öneri?
Randall Flagg

1
@Thomas HttpListener'ı yönetici olmayan modda çalıştırırken sorun yoktur.
Darrel Miller

23

Ön http://localhost:80/ek olarak kullanırsanız , Yönetici ayrıcalıklarına ihtiyaç duymadan http isteklerini dinleyebilirsiniz.


2
Örnek bir kod gönderebilir misiniz? Ben sadece bunu denedim http://localhost:80/ve bir "Erişim Reddedildi" var.
John Saunders

2
Üzgünüm, bu işe yaramıyor. Lütfen yönetici olarak çalışıp çalışmadığınızı kontrol edin, bu normal durum olmamalıdır.
Jonno

Bu işe yarayacaksa, ben bir Windows hata düşünün. Pencereler hakkında ne düşünürseniz düşünün, bunun çok temel bir seviyede olduğunu varsayalım, çok, büyük olasılıkla doğru şekilde işlemeyi özlemediler.
hoijui

26
2 yıldan fazla bir süre sonra, bu benim için şimdi .NET framework 4.5 ile Windows Server 2008 R2 üzerinde çalışıyor. httpListener.Prefixes.Add("http://*:4444/");gerçekten bir Access Deniedhata gösterir ama httpListener.Prefixes.Add("http://localhost:4444/");sorunsuz çalışın. Microsoft'un localhostbu kısıtlamalardan hariç tutulduğu anlaşılıyor. İlginçtir, httpListener.Prefixes.Add("http://127.0.0.1:4444/");hala bir Erişim Reddedildi hatası gösteriyor, bu yüzden işe yarayan tek şeylocalhost:{any port}
Tony

1
@ Teşekkürler yorumunuz aslında benim için en değerli oldu. Birkaç yapılandırmada "127.0.0.1" vardı. QA, Windows 8.1'de çalışmadığını, ancak Windows 10'da iyi olduğunu bildirdi (ve Win10'da kendimi test ettim). İşin garibi, Microsoft, Win10'da 127.0.0.1 kullanmaya izin verdi, ancak 8.1 değil (ve muhtemelen önceki sürümler), ancak yeterince emin olun, localhost iyi. Teşekkürler
Adam Plocher

20

Sözdizimi benim için yanlıştı, tırnak işaretlerini eklemelisiniz:

netsh http add urlacl url="http://+:4200/" user=everyone

aksi takdirde "Parametre yanlış"


4
Eğer bir sondaki belirtmek yoksa da iade edilebilir "parametresi yanlış" /url üzerinde
LostSalad

13

"User = Everyone" işaretini kullanmak istiyorsanız, sistem dilinize göre ayarlamanız gerekir. İngilizce'de belirtildiği gibi:

netsh http add urlacl url=http://+:80/ user=Everyone

Almancada şöyle olur:

netsh http add urlacl url=http://+:80/ user=Jeder

1
İspanyolca dil sistemlerinde şunları yapın: user = Todos
Rodrigo Rodrigues

Ayrıca, başka bir yanıtta belirtildiği gibi URL'yi tırnak içine almam gerekiyordu.
Carsten Führmann

10

Yükseklik veya netsh gerektirmeyen bir alternatif olarak, örneğin TcpListener'ı da kullanabilirsiniz.

Aşağıda bu örneğin değiştirilmiş bir alıntısı yer almaktadır: https://github.com/googlesamples/oauth-apps-for-windows/tree/master/OAuthDesktopApp

// Generates state and PKCE values.
string state = randomDataBase64url(32);
string code_verifier = randomDataBase64url(32);
string code_challenge = base64urlencodeNoPadding(sha256(code_verifier));
const string code_challenge_method = "S256";

// Creates a redirect URI using an available port on the loopback address.
var listener = new TcpListener(IPAddress.Loopback, 0);
listener.Start();
string redirectURI = string.Format("http://{0}:{1}/", IPAddress.Loopback, ((IPEndPoint)listener.LocalEndpoint).Port);
output("redirect URI: " + redirectURI);

// Creates the OAuth 2.0 authorization request.
string authorizationRequest = string.Format("{0}?response_type=code&scope=openid%20profile&redirect_uri={1}&client_id={2}&state={3}&code_challenge={4}&code_challenge_method={5}",
    authorizationEndpoint,
    System.Uri.EscapeDataString(redirectURI),
    clientID,
    state,
    code_challenge,
    code_challenge_method);

// Opens request in the browser.
System.Diagnostics.Process.Start(authorizationRequest);

// Waits for the OAuth authorization response.
var client = await listener.AcceptTcpClientAsync();

// Read response.
var response = ReadString(client);

// Brings this app back to the foreground.
this.Activate();

// Sends an HTTP response to the browser.
WriteStringAsync(client, "<html><head><meta http-equiv='refresh' content='10;url=https://google.com'></head><body>Please close this window and return to the app.</body></html>").ContinueWith(t =>
{
    client.Dispose();
    listener.Stop();

    Console.WriteLine("HTTP server stopped.");
});

// TODO: Check the response here to get the authorization code and verify the code challenge

Okuma ve yazma yöntemleri:

private string ReadString(TcpClient client)
{
    var readBuffer = new byte[client.ReceiveBufferSize];
    string fullServerReply = null;

    using (var inStream = new MemoryStream())
    {
        var stream = client.GetStream();

        while (stream.DataAvailable)
        {
            var numberOfBytesRead = stream.Read(readBuffer, 0, readBuffer.Length);
            if (numberOfBytesRead <= 0)
                break;

            inStream.Write(readBuffer, 0, numberOfBytesRead);
        }

        fullServerReply = Encoding.UTF8.GetString(inStream.ToArray());
    }

    return fullServerReply;
}

private Task WriteStringAsync(TcpClient client, string str)
{
    return Task.Run(() =>
    {
        using (var writer = new StreamWriter(client.GetStream(), new UTF8Encoding(false)))
        {
            writer.Write("HTTP/1.0 200 OK");
            writer.Write(Environment.NewLine);
            writer.Write("Content-Type: text/html; charset=UTF-8");
            writer.Write(Environment.NewLine);
            writer.Write("Content-Length: " + str.Length);
            writer.Write(Environment.NewLine);
            writer.Write(Environment.NewLine);
            writer.Write(str);
        }
    });
}

IdentityModel.OidcClient kütüphanesi için bir IBrowser uygularken HttpListener sorunu yaşadığımız için bu gerçekten yararlı oldu, bu yüzden yukarıdakilere çok benzer bir kullanım örneği.
mackie

1
Yukarıdaki kod olsa hata olduğunu belirtmek gerekir. Öncelikle UTF8 ile bir StreamWriter kullanmak bazı tarayıcılarda sorunlara neden olur, bir BOM çıktısı veya bunun gibi bir şey nedeniyle tahmin ediyorum. ASCII olarak değiştirdim ve her şey yolunda. Ayrıca, bazen veri döndürmeyeceği için verilerin akışta okunmasını beklemek için bazı kodlar ekledim.
mackie

Teşekkürler @ mackie - bu bölüm aslında doğrudan Microsoft'un kendi örneğinden alınmıştır. Gerçekten düzgün test etmediler sanırım. Cevabımı düzenleyebilirseniz devam edin ve yöntemleri düzeltin - aksi takdirde belki değişiklikleri bana gönderin ve güncelleyebilirim.
Michael Olsen

2
ASCII kullanmak yerine, new UTF8Encoding(false)bir ürün ağacının yayılmasını devre dışı bırakan aşağıdaki yapıcı kullanılmalıdır . Bunu cevapta zaten değiştirdim
Sebastian

Bu çözümü kabul edilen cevaba tercih ederim. Netsh koşmak bir kesmek gibi görünüyor. Bu sağlam bir programatik çözümdür. Teşekkürler!
Jim Gomes

7

Projenize Uygulama Bildirgesi eklerseniz uygulamanızı yönetici olarak başlatabilirsiniz.

Projenize Yeni Öğe ekleyin ve "Uygulama Bildirim Dosyası" nı seçin. <requestedExecutionLevel>Öğeyi şu şekilde değiştirin :

<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />

7

Varsayılan olarak Windows, herkes tarafından kullanılabilen aşağıdaki öneki tanımlar: http: // +: 80 / Temporary_Listen_Addresses /

Böylece şu HttpListeneryolla kayıt olabilirsiniz :

Prefixes.Add("http://+:80/Temporary_Listen_Addresses/" + Guid.NewGuid().ToString("D") + "/";

Bu bazen varsayılan olarak 80 numaralı bağlantı noktasını kullanmaya çalışan Skype gibi yazılımlarda sorunlara neden olur.


1
Skype suçluydu. Ben bağlantı noktasını değişti değil 80 olmak ve işe yaradı.
Git


2

Ben de benzer bir sorunla karşı karşıya kaldım. Eğer zaten url rezerve varsa o zaman ilk yönetici olmayan modda çalıştırmak için url silmek zorunda kalırsanız başka Erişim Engellendi hatası ile başarısız olur.

netsh http delete urlacl url=http://+:80
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.