我正在用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;
}
}
}
}
}
答案 0 :(得分:267)
是的,您可以在非管理员模式下运行HttpListener。您需要做的就是为特定URL授予权限。 e.g。
netsh http add urlacl url=http://+:80/MyUri user=DOMAIN\user
文档为here。
答案 1 :(得分:28)
我可以让它在没有管理员模式的情况下运行吗?如果有,怎么样?如果不是,如何在开始运行后让应用程序更改为管理模式?
你不能,它必须以提升的特权开始。您可以使用runas
动词重新启动它,这将提示用户切换到管理模式
static void RestartAsAdmin()
{
var startInfo = new ProcessStartInfo("yourApp.exe") { Verb = "runas" };
Process.Start(startInfo);
Environment.Exit(0);
}
答案 2 :(得分:18)
如果您使用http://localhost:80/
作为前缀,则无需管理员权限即可收听http请求。
答案 3 :(得分:16)
语法错误,您必须包含引号:
netsh http add urlacl url="http://+:4200/" user=everyone
否则我收到“参数不正确”
答案 4 :(得分:10)
如果你想使用旗帜" user = Everyone"您需要根据系统语言进行调整。在英语中如上所述:
netsh http add urlacl url=http://+:80/ user=Everyone
在德国,它将是:
netsh http add urlacl url=http://+:80/ user=Jeder
答案 5 :(得分: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
读写方法是:
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);
}
});
}
答案 6 :(得分:6)
如果将Application Manifest添加到项目中,则可以以管理员身份启动应用程序。
只需将新项添加到项目中,然后选择&#34; Application Manifest File&#34;。将<requestedExecutionLevel>
元素更改为:
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
答案 7 :(得分:5)
默认情况下,Windows定义以下每个人都可以使用的前缀: http://+:80/Temporary_Listen_Addresses/
因此,您可以通过以下方式注册HttpListener
:
Prefixes.Add("http://+:80/Temporary_Listen_Addresses/" + Guid.NewGuid().ToString("D") + "/";
这有时会导致Skype等软件出现问题,默认情况下会尝试使用端口80.
答案 8 :(得分:2)
httpListener.Prefixes.Add("http://*:4444/");
您使用“*”,因此您执行以下cmd作为管理员
netsh http add urlacl url=http://*:4444/ user=username
没有用+,必须使用*,因为你的规格*:4444~。
https://msdn.microsoft.com/en-us/library/system.net.httplistener.aspx
答案 9 :(得分:1)
谢谢, 这很有帮助。 只是要添加更多[从MS页面]:
警告
不应使用顶级通配符绑定(
http://*:8080/
和http://+:8080
)。顶级通配符绑定可以使您的应用程序面临安全漏洞。这适用于强通配符和弱通配符。使用显式主机名而不是通配符。如果您控制整个父域(与易受攻击的*.mysub.com
相对),则子域通配符绑定(例如*.com
)不存在此安全风险。有关更多信息,请参见rfc7230第5.4节。
答案 10 :(得分:0)
我也遇到了类似的问题。如果你已经保留了url,那么你必须先删除url以非管理员模式运行,否则它将失败,Access is Denied错误。
netsh http delete urlacl url=http://+:80
答案 11 :(得分:0)
不幸的是,由于某些可能与HTTPS和证书链接的原因,本机.NET HttpListener需要管理员权限,甚至对于仅HTTP协议也是如此...
优点
有趣的是,HTTP协议位于TCP协议之上,但是启动C#TCP侦听器不需要任何管理员权限即可运行。换句话说,从概念上讲,可以实现不需要管理员特权的HTTP服务器。
替代
下面是不需要管理员权限的项目示例: https://github.com/EmilianoElMariachi/ElMariachi.Http.Server
答案 12 :(得分:-1)
netsh需要管理员权限
您可以通过设置IgnoreWriteExceptions来为没有管理员权限的localhost修复此问题:
listener.IgnoreWriteExceptions = True
listener.Start()