HttpListenerアクセス​​が拒否されました


180

HTTPサーバーをC#で作成しています。

関数HttpListener.Start()を実行しようとするHttpListenerExceptionと、格言が出ます

"アクセスが拒否されました"。

Windows 7で管理モードでアプリを実行すると、正常に動作します。

管理モードなしで実行できますか?はいの場合はどうですか?そうでない場合、実行を開始した後にアプリを管理モードに変更するにはどうすればよいですか?

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

誰かがそのエラーを回避したい場合は、TcpListenerを使用してエラーを記述できます。管理者権限は必要ありません
Vlad

私は同じ問題に直面し、Visual Studio 2008 + Windows 7で「アクセス拒否」エラーを生成します。これを解決するには、Visual Studio 2008を管理モードで実行します
Mark Khor

回答:


307

はい、非管理者モードでHttpListenerを実行できます。特定のURLへのアクセス許可を付与するだけです。例えば

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

ドキュメントはこちらです。


48
これは役に立ちますが、完全にするために、このコード行で指定されたURL httpListener.Prefixes.Add("http://*:4444/");は、netshコマンド内のURLと完全に一致する必要があります。たとえば、私が持っていたのhttpListener.Prefixes.Add("http://127.0.0.1:80/");と同じnetshコマンドを実行すると、HttpListenerExceptionがスローされます。httpListener.Prefixes.Add("http://+:80/");これを理解するための正しい道に私を導いたので、あなたの助けをありがとう@Darrel Miller を変更する必要がありました!
psyklopz

10
また、「MyUri」が空の場合は末尾のスラッシュを忘れないでくださいThe parameter is incorrect。空でない場合、エラーが発生します。例:url=http://+:80/
Igor Brejc 2013年

14
非管理ユーザーのためにこれを行う方法はありますhttp://localhost:80/か?そのようなURLで1つの要求を受け取る必要のあるデスクトップアプリケーションがあり、この1つの目的のためだけに、管理者が50のデスクトップにアプリケーションをインストールする必要があるのは残念です。
John Saunders、

5
どうやらそうではない。また、ドキュメントページでは、昇格または管理者特権が必要であることについての言及はありません。したがって、これが「より賢い」TCPListenerとして機能すると想定するのは簡単です。実際には使用しないという主な理由がある場合ですが、これは文書化されていません。
デビッドフォード

4
netshを実行するには、adminが必要です(
superfly71

27

管理モードなしで実行できますか?はいの場合はどうですか?そうでない場合、実行を開始した後にアプリを管理モードに変更するにはどうすればよいですか?

できません。システム特権で起動する必要があります。runas動詞を使用して再起動できます。これにより、ユーザーは管理モードに切り替えるように求められます

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

編集:実際には、それは真実ではありません。HttpListenerは昇格された特権がなくても実行できますが、リッスンするURLのアクセス許可を与える必要があります。詳細については、Darrel Millerの回答を参照してください。


昇格された特権から始めなければならない理由を説明していただけますか?
Randall Flagg

この行 'startInfo.UseShellExecute = false;'も追加する必要があります。「Process.Start(startInfo);」の前
Randall Flagg

@Randall:これがWindowsの動作方法です...プロセスは実行中に管理モードに切り替えることができません。UseShellExecuteについて:実行している内容によって異なります。私は "notepad.exe"でコードをテストしましたが、UseShellExecute = falseなしでも問題なく機能します
Thomas Levesque

ありがとう。UseShellExecuteについて:投稿したコードを実行しようとしました。もう1つの問題は、なんらかの理由で、管理者として実行するかどうかを一度尋ねられ、その後は要求されないことです。私は再起動し、そこに何もないことを確認するためにデバッグしました。助言がありますか?
Randall Flagg

1
@Thomas非管理モードでHttpListenerを実行しても問題はありません。
Darrel Miller

23

http://localhost:80/プレフィックスとして使用する場合、管理者権限を必要とせずにhttpリクエストをリッスンできます。


2
いくつかのサンプルコードを投稿できますか?私はこれを試してみてhttp://localhost:80/、「アクセス拒否」を得ました。
John Saunders、

2
申し訳ありませんが、うまくいきません。管理者として実行しているかどうかを確認してください。これは通常のケースではありません。
ジョンノ2014年

これが機能する場合は、Windowsのバグと見なします。あなたがウィンドウについて何を考えていても、私はこれが非常に基本的なレベルであり、正しく処理するために見逃していない可能性が非常に高いと思います。
hoijui、2015年

26
2年以上後、これは.NET Framework 4.5を搭載したWindows Server 2008 R2で動作します。httpListener.Prefixes.Add("http://*:4444/");確かにAccess Deniedエラーが表示されますがhttpListener.Prefixes.Add("http://localhost:4444/");、問題なく動作します。Microsoft localhostはこれらの制限から除外されているようです。興味深いことに、httpListener.Prefixes.Add("http://127.0.0.1:4444/");依然としてアクセス拒否エラーが表示されているため、機能するのはlocalhost:{any port}
トニー

1
@Tonyありがとう、コメントは実際に私にとって最も価値がありました。いくつかの設定で「127.0.0.1」がありました。QAは、Windows 8.1では機能しなかったが、Windows 10では問題なく動作することを報告しました(Win10で自分でテストしました)。奇妙なことに、Microsoftは全員がWin10で127.0.0.1を使用することを許可しているようですが、8.1(おそらく以前のバージョン)では使用していませんが、localhostで十分です。ありがとう
Adam Plocher

20

構文は私にとって間違っていました、引用符を含める必要があります:

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

それ以外の場合は、「パラメーターが正しくありません」を受け取りました


4
「パラメータが正しくありません」は/、URLの末尾を指定しない場合にも返される可能性があります
LostSalad

13

フラグ「user = Everyone」を使用する場合は、システム言語に合わせて調整する必要があります。英語でそれは言及されたとおりです:

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

ドイツ語では次のようになります。

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

1
スペイン語のシステムでは、次のようにします。user= Todos
Rodrigo Rodrigues

さらに、別の回答で述べたように、URLを引用符で囲む必要がありました。
CarstenFührmann19年

10

昇格またはnetshを必要としない代替手段として、たとえばTcpListenerを使用することもできます。

以下は、このサンプルの変更された抜粋です。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

読み取りおよび書き込みメソッドは次のとおりです。

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ライブラリのIBrowserを実装するときにHttpListenerの問題が発生したため、非常に役立ちました。
mackie、

1
ただし、上記のコードにはバグがあることに注意してください。まず、UTF8でStreamWriterを使用すると、一部のブラウザーで問題が発生します。BOMが出力されているためか、そのようなものだと思います。私はそれをASCIIに変更し、すべて順調です。データが返されないこともあるので、ストリームでデータが読み取れるようになるのを待つコードも追加しました。
mackie、

@mackieに感謝します-その部分は実際にはMicrosoft自身のサンプルから直接取られました。彼らは本当にそれを適切にテストしなかったと思います。私の回答を編集できる場合は、先に進んでメソッドを修正してください。そうでない場合は、変更を送っていただければ更新できます。
マイケルオルセン

2
ASCIIを使用する代わりにnew UTF8Encoding(false)、BOMの発行を無効にする次のコンストラクタを使用する必要があります。私は答えですでにこれを変更しました
Sebastian

私は受け入れられた答えよりもこの解決策を好みます。netshの実行はハックのようです。これは確実なプログラムソリューションです。ありがとう!
ジム・ゴメス

7

プロジェクトにアプリケーションマニフェストを追加すると、管理者としてアプリケーションを起動できます。

プロジェクトに新しいアイテムを追加し、「アプリケーションマニフェストファイル」を選択するだけです。<requestedExecutionLevel>要素を次のように変更します。

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

7

デフォルトでは、Windowsは誰でも利用できる次のプレフィックスを定義します: http:// +:80 / Temporary_Listen_Addresses /

だからあなたはHttpListener経由であなたを登録することができます:

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

これにより、デフォルトでポート80を利用しようとするSkypeなどのソフトウェアで問題が発生することがあります。


1
犯人はスカイプだった。ポートを80 に変更しましたが、うまくいきました。
GoTo


2

私も同様の問題に直面しました。すでにURLを予約している場合、非管理モードで実行するにはまずURLを削除する必要があります。そうしないと、アクセスが拒否されたというエラーで失敗します。

netsh http delete urlacl url=http://+:80
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.