QNetworkAccessManager - Authentication bei HTTP-POST
Verfasst: 15. Januar 2009 05:06
Sorry vielleicht etwas lang, aber ich habe viele Versuche protokolliert, um das (scheinbare) Fehlverhalten genauer darzulegen.
Ich verwende QNetworkAccessManager und versuche mich gegenüber einer PHP-Seite zu authentifizieren.
Mit HTTP-GET funktioniert alles. Aber mit POST gibt es Probleme:
Ich sende eine Datei mit HTTP-POST, er lädt sie auf den Server, und der Slot authenticationRequired wird aufgerufen. Tue ich dort nichts, bekomme ich "Abbrechen gedrückt" als reply vom PHP-Script in QNetworkManager::finished(...). Das ist normales Verhalten.
Setze ich jedoch Benutzername und Passwort im QAuthenticator-Objekt, passiert nichts. Egal, was ich dort eintrage. Kein weiteres Signal wird aufgerufen (nicht im QNetworkAccessManager und nicht im QNetworkReply, welches von QNetworkAccessManager::post(...) zurückgegeben wurde.
Das PHP-Script reagiert jedoch, wie ich anhand seiner Log-Datei sehen konnte: Sind die Zugangsdaten korrekt, fährt es fort, sind sie falsch, sendet er die 401-Header erneut. Qt scheint auf nichts zu reagieren. Sind die Zugangsdaten richtig und fährt das Script fort (bzw. wird es durch wen auch immer erneut aufgerufen), sind die $_POST/$_FILES-Variablen bei diesem Durchlauf jedoch nicht mehr gefüllt. Wieso? Über ein HTML-Formular mit Firefox funktioniert das, selbst wenn man mehrmals falsche Zugangsdaten eingibt. Firefox scheint jedoch die Datei nach jeder Zugangsdateneingabe erneut hochzuladen.
Also dachte mir, vielleicht muss ich den request erneut senden. Im authenticationRequired-Signal habe ich dann "QNetworkReply *newReply = manager->post( reply->request(), *m_bytes );" hinzugefügt, nachdem ich die Zugangsdaten gesetzt habe. Ergebnis: Das PHP-Script wird 2x aufgerufen und sendet die 401-Header, anschließend wird es 2x aufgerufen mit erfolgreicher Authentifizierung aber ohne $_POST/$_FILES-Daten. Qt hat aber nur 1x authenticationRequired() aufgerufen, und für meinen 2. Post-Befehl lediglich QNetworkReply::uploadProgress(...) beim newReply. Wegen dem einen authenticationRequired() aber den zwei erfolgreichen Authentifizierungen, nehme ich an, dass QNetworkAccessManager intern noch irgendwie funktioniert. Aber ich bekomme keine Signale. Und die leeren POST-Variablen sind auch dumm.
Setze ich falsche Zugangsdaten, sendet das PHP-Script zum Schluss die Header neu, also insgesamt 4x, bei den letzten 2 ohne Post-Daten. Und Qt ruft beim 2. Mal auch kein authenticationRequired() mehr auf.
Ich weiß einfach nicht weiter.
Ein "reply->abort();" im authenticationRequired() lässt den manager und das reply ein finished() senden, aber den manager kann ich danach trotzdem nicht weiter verwenden, um z.B. den request mit seinen nun gespeicherten Zugangsdaten zu wiederholen (das reply sendet uploadProgress(...), das wars dann wieder, der manager sagt garnichts mehr).
Ich hoffe, ich mache etwas grundlegend falsch, und jemand weiß, was... Dass erst die Dateien hochgeladen werden, und danach erst authentifizert werden kann, das kanns ja sowieso auch nicht sein.. aber es funktioniert halt mit dem HTML-Formular, und notfalls ist das auch nicht tragisch..
Beginn des PHP-Scripts (das Verarbeiten der POST-Anfrage habe ich weggelassen):
FaS
Ich verwende QNetworkAccessManager und versuche mich gegenüber einer PHP-Seite zu authentifizieren.
Mit HTTP-GET funktioniert alles. Aber mit POST gibt es Probleme:
Ich sende eine Datei mit HTTP-POST, er lädt sie auf den Server, und der Slot authenticationRequired wird aufgerufen. Tue ich dort nichts, bekomme ich "Abbrechen gedrückt" als reply vom PHP-Script in QNetworkManager::finished(...). Das ist normales Verhalten.
Setze ich jedoch Benutzername und Passwort im QAuthenticator-Objekt, passiert nichts. Egal, was ich dort eintrage. Kein weiteres Signal wird aufgerufen (nicht im QNetworkAccessManager und nicht im QNetworkReply, welches von QNetworkAccessManager::post(...) zurückgegeben wurde.
Das PHP-Script reagiert jedoch, wie ich anhand seiner Log-Datei sehen konnte: Sind die Zugangsdaten korrekt, fährt es fort, sind sie falsch, sendet er die 401-Header erneut. Qt scheint auf nichts zu reagieren. Sind die Zugangsdaten richtig und fährt das Script fort (bzw. wird es durch wen auch immer erneut aufgerufen), sind die $_POST/$_FILES-Variablen bei diesem Durchlauf jedoch nicht mehr gefüllt. Wieso? Über ein HTML-Formular mit Firefox funktioniert das, selbst wenn man mehrmals falsche Zugangsdaten eingibt. Firefox scheint jedoch die Datei nach jeder Zugangsdateneingabe erneut hochzuladen.
Also dachte mir, vielleicht muss ich den request erneut senden. Im authenticationRequired-Signal habe ich dann "QNetworkReply *newReply = manager->post( reply->request(), *m_bytes );" hinzugefügt, nachdem ich die Zugangsdaten gesetzt habe. Ergebnis: Das PHP-Script wird 2x aufgerufen und sendet die 401-Header, anschließend wird es 2x aufgerufen mit erfolgreicher Authentifizierung aber ohne $_POST/$_FILES-Daten. Qt hat aber nur 1x authenticationRequired() aufgerufen, und für meinen 2. Post-Befehl lediglich QNetworkReply::uploadProgress(...) beim newReply. Wegen dem einen authenticationRequired() aber den zwei erfolgreichen Authentifizierungen, nehme ich an, dass QNetworkAccessManager intern noch irgendwie funktioniert. Aber ich bekomme keine Signale. Und die leeren POST-Variablen sind auch dumm.
Setze ich falsche Zugangsdaten, sendet das PHP-Script zum Schluss die Header neu, also insgesamt 4x, bei den letzten 2 ohne Post-Daten. Und Qt ruft beim 2. Mal auch kein authenticationRequired() mehr auf.
Ich weiß einfach nicht weiter.
Ein "reply->abort();" im authenticationRequired() lässt den manager und das reply ein finished() senden, aber den manager kann ich danach trotzdem nicht weiter verwenden, um z.B. den request mit seinen nun gespeicherten Zugangsdaten zu wiederholen (das reply sendet uploadProgress(...), das wars dann wieder, der manager sagt garnichts mehr).
Ich hoffe, ich mache etwas grundlegend falsch, und jemand weiß, was... Dass erst die Dateien hochgeladen werden, und danach erst authentifizert werden kann, das kanns ja sowieso auch nicht sein.. aber es funktioniert halt mit dem HTML-Formular, und notfalls ist das auch nicht tragisch..
Beginn des PHP-Scripts (das Verarbeiten der POST-Anfrage habe ich weggelassen):
Die Dokumentation sagt nichts weiter dazu, außer, dass man sie so verstehen könnte, dass die Zugangsdaten erst beim nächsten request verwendet werden. Aber wenn das so wäre, würde sich bestimmt nicht dieses "andere" Verhalten zeigen, wenn man denn die Daten setzt. Und beim nächsten Request reagiert der manager ja sowieso nicht mehr:<?php
$file = $_POST['userdir'].$_FILES['userfile']['name'];
$handle = fopen( "log.txt", 'a' );
fwrite( $handle, "file: $file \n" );
if( !isset( $_SERVER['PHP_AUTH_USER'] ) || $_SERVER['PHP_AUTH_USER'] != "user" || $_SERVER['PHP_AUTH_PW'] != "pass" )
{
// Log
fwrite( $handle, "sending authentication request\n" );
fclose( $handle );
header( 'WWW-Authenticate: Basic realm="Zugangsdaten"' );
header( 'HTTP/1.0 401 Unauthorized' );
echo 'Abbrechen gedrückt';
exit;
}
// Log
fwrite( $handle, "authentication successful\n" );
fclose( $handle );
echo 'Erfolgreich authentifiziert.';
Ich bitte um Hilfe,void QNetworkAccessManager::authenticationRequired ( QNetworkReply * reply, QAuthenticator * authenticator ) [signal]
This signal is emitted whenever a final server requests authentication before it delivers the requested contents. The slot connected to this signal should fill the credentials for the contents (which can be determined by inspecting the reply object) in the authenticator object.
QNetworkAccessManager will cache the credentials internally and will send the same values if the server requires authentication again, without emitting the authenticationRequired() signal. If it rejects the credentials, this signal will be emitted again.
FaS