HttpListener访问被拒绝

Ran*_*agg 159 uac httplistener windows-7 c#-4.0

我在C#中编写HTTP服务器.

当我尝试执行该功能时,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;
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Dar*_*ler 286

是的,您可以在非管理员模式下运行HttpListener.您需要做的就是为特定URL授予权限.例如

netsh http add urlacl url=http://+:80/MyUri user=DOMAIN\user
Run Code Online (Sandbox Code Playgroud)

文档在这里.

  • 这很有用,但为了完整起见,在这行代码中指定的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,因为你让我走上正确的道路来解决这个问题! (43认同)
  • 有没有办法为非管理用户执行此操作,即使对于`http:// localhost:80 /`?我有一个桌面应用程序,需要在这样的URL上接收一个请求,并且要求管理员将其安装在50个桌面上似乎是一种耻辱,仅用于此目的. (14认同)
  • 如果"MyUri"为空,请不要忘记尾部斜杠,否则您将得到"参数不正确"错误.示例:`url = http:// +:80 /` (9认同)
  • 显然不是.文档页面中也没有提到要求提升或管理权限.所以很容易假设这将作为一个"更聪明"的TCPListener,而实际上有一个主要原因不使用它 - 但这没有记录. (4认同)
  • @DarrelMiller 这并不能阻止恶意软件打开本地服务器。您仍然可以创建一个 HTTP 服务器,只是不能使用 HTTP.sys 或“HttpListener”来完成它,例如可以调用“TcpListener.Create(4444).Start()”并在其上实现 HTTP/1.1。所以我不明白为什么存在这个(看似未记录的)权限检查。 (4认同)
  • 运行netsh需要管理员;( (3认同)

Tho*_*que 27

我可以在没有管理员模式的情况下运行吗 如果有,怎么样?如果不是,如何在开始运行后让应用程序更改为管理模式?

你不能,它必须以提升的特权开始.您可以使用runas动词重新启动它,这将提示用户切换到管理模式

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

编辑:实际上,那不是真的; HttpListener可以在没有提升权限的情况下运行,但您需要为要监听的URL授予权限.有关详细信息,请参阅Darrel Miller的答案.


Ehs*_*edi 22

如果http://localhost:80/用作前缀,则可以在不需要管理权限的情况下侦听http请求.

  • 所以两年多以后,这对我来说在Windows Server 2008 R2上使用.NET Framework 4.5.`httpListener.Prefixes.Add("http://*:4444 /");`确实显示`Access Denied`错误但是`httpListener.Prefixes.Add("http:// localhost:4444 /");`work没有任何问题.看起来微软将`localhost`排除在这些限制之外.有趣的是,`httpListener.Prefixes.Add("http://127.0.0.1:4444/");`仍显示Access Denied错误,所以唯一有效的是`localhost:{any port} (22认同)
  • 你能发布一些示例代码吗?我刚刚用 `http://localhost:80/` 尝试了这个,得到了一个“拒绝访问”。 (2认同)
  • 抱歉,这似乎不起作用。请检查您是否以管理员身份运行,这不应该是正常情况。 (2认同)
  • @Tony 谢谢你的评论对我来说实际上是最有价值的。我在几个配置中有“127.0.0.1”。QA 报告说它不能在 Windows 8.1 上运行,但在 Windows 10 中运行得很好(我自己在 Win10 中测试过)。奇怪的是,似乎微软已经允许每个人在 Win10 中使用 127.0.0.1 而不是 8.1(并且可能是以前的版本),但果然,localhost 很好。谢谢 (2认同)

Dav*_*ave 20

语法对我来说是错误的,你必须包括引号:

netsh http add urlacl url="http://+:4200/" user=everyone
Run Code Online (Sandbox Code Playgroud)

否则我收到"参数不正确"

  • 如果你没有在url上指定尾随的`/`,也可以返回"参数不正确" (4认同)

Chr*_*ann 13

如果您想使用"user = Everyone"标志,您需要将其调整为您的系统语言.在英语中如上所述:

netsh http add urlacl url=http://+:80/ user=Everyone
Run Code Online (Sandbox Code Playgroud)

在德国,它将是:

netsh http add urlacl url=http://+:80/ user=Jeder
Run Code Online (Sandbox Code Playgroud)

  • 波兰语 user=wszyscy (2认同)

Mic*_*sen 9

作为不需要提升或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
Run Code Online (Sandbox Code Playgroud)

读写方法是:

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);
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

  • 应该使用以下构造函数```new UTF8Encoding(false)```来禁用BOM的发送,而不是使用ASCII.我已经在答案中改变了这一点 (2认同)

小智 7

httpListener.Prefixes.Add("http://*:4444/");
Run Code Online (Sandbox Code Playgroud)

您使用“*”,因此您以管理员身份执行以下 cmd

netsh http add urlacl url=http://*:4444/ user=username
Run Code Online (Sandbox Code Playgroud)

不用+,必须用*,因为你指定*:4444~。

https://msdn.microsoft.com/en-us/library/system.net.httplistener.aspx


R.T*_*tov 6

如果将Application Manifest添加到项目中,则可以以管理员身份启动应用程序.

只需将新项添加到项目中,然后选择"应用程序清单文件".将<requestedExecutionLevel>元素更改为:

<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
Run Code Online (Sandbox Code Playgroud)


Seb*_*ian 5

默认情况下,Windows定义以下每个人都可用的前缀: http:// +:80/Temporary_Listen_Addresses /

所以你可以注册你的HttpListener通道:

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

这有时会导致Skype等软件出现问题,默认情况下会尝试使用端口80.