2011-08-29 16 views
19

Ho un servizio REST WCF ospitato all'interno di un servizio Windows e desidero inviare l'intestazione HTTP Access-Control-Allow-Origin (definita come parte di CORS) con ogni risposta.Supporto CORS all'interno dei servizi REST WCF

mio tentata soluzione era quella di avere qualcosa di simile a quanto segue in un IDispatchMessageInspector implementazione:

public void BeforeSendReply(ref Message reply, object correlationState) 
{ 
    var httpResponse = reply.Properties["httpResponse"] as HttpResponseMessageProperty; 
    if (httpResponse != null) 
    { 
     // test of CORS 
     httpResponse.Headers["Access-Control-Allow-Origin"] = "*"; 
    } 
} 

Normalmente questo avrebbe funzionato, ma purtroppo il mio servizio utilizza anche HTTP basic authorization, il che significa che quando arriva una richiesta senza l'autorizzazione intestazione, WCF invia automaticamente una risposta 401 chiedendo le credenziali. Purtroppo WCF non chiama il mio IDispatchMessageInspector durante questo scambio iniziale, quindi l'intestazione Access-Control-Allow-Origin non viene aggiunta allo scambio iniziale.

Il problema si verifica quando provo a chiamare il servizio da un browser. CORS specifica che le richieste di origine incrociata dovrebbero essere consentite solo se il dominio di origine corrisponde al dominio elencato nell'intestazione di risposta Access-Control-Allow-Origin (* corrisponde a tutti i domini). Sfortunatamente, quando il browser vede la risposta iniziale 401 senza l'intestazione Access-Control-Allow-Origin, impedisce l'accesso (in base allo same origin policy).

È possibile aggiungere un'intestazione alla risposta 401 iniziale inviata automaticamente da WCF?

+0

Sei mai arrivato ovunque con questo? –

risposta

6

Per ottenere ciò che si desidera è necessario gestire autonomamente l'autorizzazione che è possibile mediante impelacmentazione + registrazione di un HttpModule ... lì si emetterebbe il 401 e con esso qualsiasi intestazione http che si desidera ... c'è anche un implementazione di esempio qui su SO - vedi Adding basic HTTP auth to a WCF REST service

EDIT - dopo il commento da OP:

dal commento del PO dice che è self-hosting la soluzione non è con HTTPModule, ma in realtà con IDispatchMessageInspector.BeforeSendReply e con IDispatchMessageInspector.AfterReceiveRequest .

L'autorizzazione deve essere configurata su "Nessuno" e personalizzata implementata/gestita in IDispatchMessageInspector - in questo modo è possibile aggiungere qualsiasi intestazione quando si emette un 401. Altrimenti il ​​runtime che gestisce l'autenticazione di base non chiamerebbe il tuo IDispatchMessageInspector prima di Auth corretto/positivo.

Anche se questo funziona Attenzione che questo significa implementare il codice di sicurezza-sensitiv te stesso e la necessità di prendere appriopriate provvedimento al fine di garantire la corretta attuazione così ...

+0

Grazie per la risposta. Il mio servizio deve essere un servizio Windows autonomo, non ospitato da IIS. La roba di autenticazione di base HTTP nel mio servizio funziona alla grande. CORS funziona anche bene (supponendo che disabiliti l'autenticazione di base). Il problema si verifica solo quando si configura HTTP di base e CORS su un servizio auto-ospitato. Se dovessi ospitare il servizio in IIS, configurerei IIS per inviare le intestazioni di risposta CORS su ogni richiesta e utilizzare un HttpModule per l'autenticazione di base HTTP. – Kevin

+0

ok - guarda la mia modifica ... la soluzione era già a metà strada ... è necessario implementare un altro metodo e modificare la configurazione ... – Yahia

+0

Impostazione clientCredentialType = "Nessuno" e la consegna manuale dell'ispezione funziona quasi. È possibile inviare la risposta 401, ma WCF non consente di impostare l'intestazione di risposta dell'autenticazione WWW. Il tentativo di impostare l'autenticazione WWW all'interno del codice fa sì che WCF restituisca un 504. Senza l'autenticazione WWW, il browser non richiederà le credenziali. – Kevin

22

Questo ragazzo mi ha salvato la giornata.

http://blogs.microsoft.co.il/blogs/idof/archive/2011/07.aspx

ho intenzione di mettere alcune delle sue note qui, nel caso in cui la pagina web muore un giorno. (io odio trovando "La tua risposta è proprio qui" link, e quindi il collegamento è morto.)

<behaviors> 
    <endpointBehaviors> 
    <behavior name="webSupport"> 
     <webHttp /> 
     <CorsSupport /> 
    </behavior> 
    </endpointBehaviors> 
</behaviors> 
<extensions> 
    <behaviorExtensions> 
    <add name="CorsSupport" type="WebHttpCors.CorsSupportBehaviorElement, WebHttpCors, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> 
    </behaviorExtensions> 
</extensions> 
<services> 
    <service name="Service.JSonService"> 
    <endpoint address="http://localhost:8080" behaviorConfiguration="webSupport” binding="webHttpBinding" contract="Service.IJSonService" /> 
    </service> 
</services> 

Ora, dovete trovare la sua biblioteca scaricabile chiamato "WebHttpCors.dll".

Ma c'è abbastanza (sopra) per aiutarti a google/bing verso una risoluzione.

La parte che mi ha lanciato per un ciclo (nel mio scenario) è che IE stava funzionando, ma Firefox non funzionava.

La mia pagina originario era:

http://localhost:53692/test/WCFCallTestViaJQ14.htm 

Quindi il mio servizio e ':

http://localhost:8002/MyWCFService/MyWCFMethodByWebGet?state=NC&city=Raleigh 

così ho dovuto localhost < < - >> traffico localhost.

**** Ma i porti erano diversi. (53692 e 8002) ****

IE era ok con esso. Firefox non era d'accordo.

Quindi devi ricordare che ciascun browser gestisce le loro richieste .Send() in modo diverso (all'interno di JQUERY).

Tutto ha senso ora.

//JavaScript snipplet 

if (window.XMLHttpRequest) { 

    returnObject = new XMLHttpRequest(); 

} else if (window.ActiveXObject) { 

    returnObject = new ActiveXObject("Microsoft.XMLHTTP"); 

} else { 

msg = "Your browser doesn't support AJAX!"; 

} 

Ecco alcune parole chiave, frasi che ho googling/binging che alla fine mi ha portato da qualche parte.

Result: [Exception... "Component returned failure code: 0x80040111 (NS_ERROR_NOT_AVAILABLE) [nsIXMLHttpRequest.statusText]" nsresult: "0x80040111 (NS_ERROR_NOT_AVAILABLE)" location: "JS frame :: http://localhost:53692/test/WCFCallTestViaJQ14.htm :: HandleJQueryError :: line 326" data: no] 


XMLHttpRequest Send "NS_ERROR_FAILURE" 

JQuery Ajax WCF Self Hosted CORS JSON 
+0

Upvote per tutti i dettagli. Continuate la buona battaglia contro il link rot! – codekaizen

Problemi correlati