web-dev-qa-db-fra.com

Accès HttpListener refusé

J'écris un serveur HTTP en C #.

Lorsque j'essaie d'exécuter la fonction HttpListener.Start(), je reçois un HttpListenerException en disant

"Accès refusé".

Lorsque je lance l'application en mode administrateur dans Windows 7, cela fonctionne bien.

Puis-je le faire fonctionner sans mode administrateur? si oui comment? Si ce n'est pas le cas, comment puis-je faire basculer l'application en mode administrateur après le démarrage?

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;
                }
            }
        }
    }
}
152
Randall Flagg

Oui, vous pouvez exécuter HttpListener en mode non-administrateur. Tout ce que vous avez à faire est d’accorder des autorisations à cette URL. par exemple.

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

La documentation est ici .

278
Darrel Miller

Puis-je le faire fonctionner sans mode administrateur? si oui comment? Si ce n'est pas le cas, comment puis-je faire basculer l'application en mode administrateur après le démarrage?

Vous ne pouvez pas, il faut commencer par des privilèges élevés. Vous pouvez le redémarrer avec le verbe runas, qui invitera l'utilisateur à passer en mode administrateur.

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

EDIT: en fait, ce n'est pas vrai; HttpListener peut fonctionner sans privilèges élevés, mais vous devez donner l'autorisation pour l'URL sur laquelle vous souhaitez écouter. Voir réponse de Darrel Miller pour plus de détails.

27
Thomas Levesque

Si tu utilises http://localhost:80/ comme préfixe, vous pouvez écouter les requêtes http sans avoir besoin de privilèges administratifs.

19
Ehsan Mirsaeedi

La syntaxe était fausse pour moi, vous devez inclure les guillemets:

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

sinon j'ai reçu "Le paramètre est incorrect"

17
Dave

Si vous souhaitez utiliser le drapeau "utilisateur = Tout le monde", vous devez l’adapter à la langue de votre système. En anglais c'est comme mentionné:

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

En allemand ce serait:

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

Comme alternative ne nécessitant pas d'élévation ni de netsh, vous pouvez également utiliser TcpListener, par exemple.

Ce qui suit est un extrait modifié de cet exemple: 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

Les méthodes de lecture et d'écriture étant:

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);
        }
    });
}
9
Michael Olsen

Vous pouvez démarrer votre application en tant qu'administrateur si vous ajoutez un manifeste d'application à votre projet.

Ajoutez simplement un nouvel élément à votre projet et sélectionnez "Fichier du manifeste de l'application". Changer la <requestedExecutionLevel> élément à:

<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
6
R.Titov

Par défaut, Windows définit le préfixe suivant, accessible à tous: http: // +: 80/Temporary_Listen_Addresses /

Vous pouvez donc enregistrer votre HttpListener via:

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

Cela pose parfois des problèmes avec des logiciels tels que Skype qui essaieront d’utiliser le port 80 par défaut.

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

vous utilisez "*" pour exécuter la commande suivante en tant qu'administrateur

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

no use +, doit utiliser *, car vous spécifiez *: 4444 ~.

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

3
NamedStar

netsh nécessite des droits d'administrateur

Vous pouvez résoudre ce problème pour localhost sans droits d'administrateur en définissant IgnoreWriteExceptions:

listener.IgnoreWriteExceptions = True
listener.Start()
0
Mike Twc

J'ai également rencontré un problème similaire.Si vous avez déjà réservé l'URL, vous devez d'abord supprimer l'URL à exécuter en mode non-administrateur, sinon il échouera avec l'erreur Access is Denied.

netsh http delete urlacl url=http://+:80
0
vivek nuna