17 Stimmen

Hinzufügen von impliziten SOAP-Kopfzeilen zu WSDL

Meine Frage ist ähnlich wie diese. Wie übergibt man einen Soap-Header, wenn er in WSDL nicht definiert ist? Aber es ist anders.

Für einen Webdienst, den ich verwende, benötigen alle Methoden eine Authentifizierung, die im Klartext in einem SOAP-Header gesendet wird. Meine WSDL enthält jedoch keine Soap-Header-Informationen. Ich habe ein benutzerdefiniertes Plattform-Tool, das ich verwenden muss, um Code aus der WSDL zu generieren. Da die Header-Informationen nicht verfügbar sind, kann ich die generierte Klasse nicht direkt verwenden - ich möchte den Code nicht manuell ändern, um den Header zu integrieren.

Ich habe versucht, den SOAP-Header in der WSDL anzugeben, konnte aber nicht die richtigen Namespaces erhalten. Die WSDL ist hier https://stage.totalcheck.sensis.com.au/service/webservice?wsdl und der SOAP-Header lautet wie folgt:

    <soapenv:Header>
        <wsse:Security>
            <wsse:UsernameToken>
                <wsse:Username>username</wsse:Username>
                <wsse:Password>password</wsse:Password>
            </wsse:UsernameToken>
        </wsse:Security>
   </soapenv:Header>

Kann mir jemand helfen? Danke!

20voto

vanto Punkte 3084

Aus konzeptioneller Sicht ist WSDL nicht dazu gedacht, Header zu definieren. WSDL dient nur zur Definition der funktionalen Aspekte eines Dienstes, wie Operationen, Nachrichten, Bindungen und Endpunkte. Nachrichten und Bindungen definieren, wie die Nutzlast von Nachrichten kodiert und formatiert werden sollte.

Die Kopfzeilen von SOAP-Nachrichten gehören jedoch nicht zur Nutzlast. Sie werden typischerweise für die Konfiguration von nicht-funktionalen Eigenschaften eines SOAP-Prozessors verwendet. Die Sicherheit ist eine solche nicht-funktionale Eigenschaft. Der funktionale Aspekt der Nutzlast wird nicht beeinträchtigt. Es wird lediglich sichergestellt, dass die Kommunikation gesichert ist, und der WS-Tool-Stack, nicht die Dienstimplementierung, sollte sich darum kümmern.

Das fehlende Stück ist nun ein Standard, der es ermöglicht, WSDL-Diensten einige nicht-funktionale Anforderungen beizufügen, so dass Codegeneratoren automatisch ableiten können, welche Header gesendet und/oder verstanden werden müssen, um die nicht-funktionale Eigenschaft wie gewünscht zu erfüllen - ohne sich manuell mit Header-Feldern befassen zu müssen. Dieser Standard existiert und heißt WS-Policy . Eine Richtlinie enthält in der Regel eine Reihe von Alternativen, die eine Reihe von Anforderungen festlegen, die sowohl der Anbieter als auch der Verbraucher erfüllen können sollten. Wenn zwei Dienste miteinander interagieren sollen, werden beide Policies genommen und eine so genannte "effektive Policy" berechnet. Sie definiert die gemeinsamen nicht-funktionalen Anforderungen. Anhand dieser Informationen können sich Anbieter und Verbraucher so konfigurieren, dass sie die erforderlichen Header, wie die WS-Security-Header, hinzufügen. WS-SecurityPolicy definiert auch eine Reihe von Richtlinien, die verwendet werden können. WS-PolicyAttachment definiert, wie solche Richtlinien an eine WSDL angehängt werden können.

Es gibt Codegeneratoren, die mit WS-Policies umgehen können, z.B. Metro oder Axis2

4voto

Roger Punkte 49

Sie können Soap-Header-Informationen zu Methodenaufrufen hinzufügen, indem Sie die Methoden in der aus der wsdl generierten Proxy-Klasse mit dem SoapHeader-Attribut ausstatten.

Zum Beispiel generiert wsdl.exe die Client-Proxy-Klasse Reference.cs für die Web-Service-Referenz, wenn Sie "Web-Referenz hinzufügen". In dem oben erwähnten Link https://stage.totalcheck.sensis.com.au/service/webservice?wsdl Es gibt eine Nachricht suggestAddress, die in eine Methode in der generierten reference.cs Client-Proxy-Code-Datei übersetzt wird, wenn Sie eine Web-Referenz aus Visual Studio hinzufügen. Wenn diese Methode aufgerufen wird, ist standardmäßig kein Header im Soap-Umschlag vorhanden. Um dem Umschlag für diese Anfrage einen SoapHeader hinzuzufügen, fügen Sie ein [SoapHeader("Security")] Attribut am Anfang der SuggestAddress-Methode in der generierten Klasse Reference.cs hinzu, wobei "Security" eine Klasse ist, die von der Basisklasse SoapHeader erbt.

Für den oben genannten erforderlichen Security SoapHeader würden Sie beispielsweise die folgenden Klassen erstellen,

public partial class Security : SoapHeader
{
    public UserNameToken UserNameToken { get; set; }
}

public partial class UserNameToken
{
    public string UserName { get; set; }
    public string Password { get; set; }
}

Dann würden Sie die SuggestAddress-Methode in der reference.cs wie folgt dekorieren,

[SoapHeader("Security")]
public suggestAddressesResult suggestAddresses([System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] addressSearch search) {
        object[] results = this.Invoke("suggestAddresses", new object[] {search});
        return ((suggestAddressesResult)(results[0]));
    }

Dadurch wird sichergestellt, dass jeder Umschlag, der beim Aufruf der Methode suggestAddress erstellt wird, einen Sicherheitskopf enthält, der wie der oben genannte aussieht,

<soapenv:Header>
    <wsse:Security>
        <wsse:UsernameToken>
            <wsse:Username>username</wsse:Username>
            <wsse:Password>password</wsse:Password>
        </wsse:UsernameToken>
    </wsse:Security>

1voto

b_levitt Punkte 6693

Der Schlüssel zu dieser Frage war für mich die Erkenntnis, dass die fraglichen Header dem WS-Security-Standard entsprechen (worauf einige hingewiesen haben).

Wenn Ihr Proxy-Erzeugungstool "benutzerdefiniert" ist, scheint es logisch, dass Sie einen Schalter haben, um die Header für WS-Security automatisch hinzuzufügen. Wenn Sie jedoch WSDL.exe ("Add Web Reference" in Visual Studio) verwenden, sollten Sie Folgendes in Betracht ziehen svcutil.exe stattdessen ("Add Service Reference").

Wenn Sie einen WCF-Proxy verwenden, können Sie die angegebene Konfiguration außer Kraft setzen und WCF erlauben, die Header für Sie hinzuzufügen:

<security mode="TransportWithMessageCredential">
    <transport clientCredentialType="None" proxyCredentialType="None" realm="" />
    <message clientCredentialType="UserName" algorithmSuite="Default" />
</security>

Von dort aus können Sie das Passwort festlegen:

RemoteSvcProxy.TheirClient client = new RemoteSvcProxy.TheirClient();
client.ClientCredentials.UserName.UserName = "uname";
client.ClientCredentials.UserName.Password = "pwd";

Ich weiß nicht, was für ein benutzerdefiniertes Tool Sie verwenden, aber vielleicht hat das Framework, auf dem es basiert, ähnliche Konfigurationsoptionen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X