Pregunta

Estoy escribiendo un servidor HTTP en C#.

Cuando intento ejecutar la función HttpListener.Start() Tengo un HttpListenerException dicho

"Acceso denegado".

Cuando ejecuto la aplicación en modo administrador en Windows 7 funciona bien.

¿Puedo hacer que se ejecute sin el modo de administración? Si es así, ¿cómo? Si no, ¿cómo puedo hacer que la aplicación cambie al modo de administración después de comenzar a ejecutar?

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;
                }
            }
        }
    }
}
¿Fue útil?

Solución

Sí, puede ejecutar httplistener en modo no admino. Todo lo que necesita hacer es otorgar permisos a la URL particular. p.ej

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

La documentación es aquí.

Otros consejos

¿Puedo hacer que se ejecute sin el modo de administración? Si es así, ¿cómo? Si no, ¿cómo puedo hacer que la aplicación cambie al modo de administración después de comenzar a ejecutar?

No puedes, tiene que comenzar con privilegios elevados. Puedes reiniciarlo con el runas verbo, que le pedirá al usuario que cambie al modo de administración

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

Editar: en realidad, eso no es cierto; Httplistener puede funcionar sin privilegios elevados, pero debe dar permiso para la URL en la que desea escuchar. Ver Respuesta de Darrel Miller para detalles.

Si utiliza http://localhost:80/ Como prefijo, puede escuchar solicitudes HTTP sin necesidad de privilegios administrativos.

La sintaxis estaba mal para mí, debes incluir las citas:

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

de lo contrario, recibí "el parámetro es incorrecto"

En caso de que desee usar el indicador "User = todos", debe ajustarlo a su idioma del sistema. En inglés es como se mencionó:

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

En alemán sería:

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

Como alternativa que no requiere elevación o NETSH, también puede usar TCPlistener, por ejemplo.

El siguiente es un extracto modificado de esta muestra: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

Los métodos de lectura y escritura son:

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

Puede iniciar su aplicación como administrador si agrega manifiesto la aplicación a su proyecto.

Simplemente agregue un nuevo elemento a su proyecto y seleccione "Archivo de manifiesto de la aplicación". Cambiar el <requestedExecutionLevel> elemento a:

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

Por defecto, Windows define el siguiente prefijo que está disponible para todos:http: //+: 80/temporal_listen_addresses/

Para que pueda registrar su HttpListener a través de:

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

Esto a veces causa problemas con software como Skype que intentarán utilizar el puerto 80 de forma predeterminada.

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

Usas "*" para ejecutar el siguiente cmd como administrador

netsh http add urlacl url=http://*:4444/ user=username

Sin uso +, debe usar *, porque usted especifica *: 4444 ~.

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

También enfrenté un problema similar. Si ya ha reservado la URL, primero debe eliminar la URL para ejecutar en modo no administrador, de lo contrario, fallará con acceso.

netsh http delete urlacl url=http://+:80

NetSH requiere derechos de administrador

Puede solucionar eso para localhost sin derechos de administrador estableciendo IgnoreWriteExcepciones:

listener.IgnoreWriteExceptions = True
listener.Start()
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top