7

Ho un WebApi protetto con Basic Auth che viene applicato all'intera API utilizzando un AuthorizationFilterAttribute. Ho anche Hub SignalR seduti su molti dei miei controller Api.Utilizzo di ajaxSetup beforeSend per Basic Auth sta interrompendo la connessione SignalR

Accanto a questo ho una pagina web che fa uso del mio WebApi. La pagina Web è in gran parte scritto in Backbone, così, al fine di effettuare chiamate al mio WebAPI protetta, ho aggiunto il seguente jquery

$.ajaxSetup({ 
    beforeSend: function (jqXHR, settings) { 
     jqXHR.setRequestHeader('Authorization', 'Basic ' + Token); 
     return true; 
    } 
}); 

Questo funziona per comunicare con i miei controllori Api, ma aggiungendo il codice di cui sopra si è rotto il il collegamento al mio SignalR Mozzi, in particolare:

XMLHttpRequest cannot load http://localhost:50000/signalr/negotiate?_=1366795855194. 
Request header field Authorization is not allowed by Access-Control-Allow-Headers. 

Rimozione della linea di jqXHR.setRequestHeader() ripristina la mia connessione Hub SignalR ma rompe le chiamate API.

luce di quanto sopra, avrei potuto fare qualcosa hacky e impostare solo l'intestazione richiesta se la richiesta viene fatta non è a/signalr ma che appena si sente sporca ...

C'è un modo più pulito intorno a questo?

Sto facendo qualcosa di sciocco? Qualcun altro ha corso a questo?

risposta

7

Quello che non ho menzionato prima è che ho un DelegatingHandler che rimanda le intestazioni corrette per ogni richiesta in arrivo al mio WebAPI. Ciò funziona perfettamente per qualsiasi richiesta al mio WebApi ma ho assunto erroneamente che ciò si applicherebbe anche alle richieste SignalR.

Come SignalR si basa su diversi metodi di trasporto diversi, non sembra ragionevole supporre ho accesso alle intestazioni di autorizzazione, in primo luogo - non sono un requisito di tutte le implementazioni WebSockets per esempio (see here)

La mia soluzione attuale è stata utilizzare SignalP HubPipeline (detailed here). Usando questo, credo di poter passare le credenziali di autenticazione di base in una stringa di query e di scrivere un modulo separato per la gestione di autorizzazione per le richieste SignalR:


passando la stringa di query

$.connection.hub.qs = "auth=" + MyBase64EncodedAuthString; 

il filtro

public class SignalrBasicAuthFilterAttribute: Attribute, IAuthorizeHubConnection { 

    public bool AuthorizeHubConnection(HubDescriptor hubDescriptor, IRequest request) { 
     var authString = request.QueryString["auth"]; 

     // ... parse, authorize, etc ... 

     return true; 
    } 

} 

Registrazione t egli Filtro

var globalAuthorizer = new SignalrBasicAuthFilterAttribute(); 
GlobalHost.HubPipeline.AddModule(new AuthorizeModule(globalAuthorizer, globalAuthorizer)); 

Inoltre ...

noti che perché non è un presupposto affidabile per inviare un'intestazione di autorizzazione con le richieste SignalR, per le ragioni di cui sopra, sto ancora filtraggio mia $ .ajaxSetup per effetto solo richieste-SignalR non:

$.ajaxSetup({ 
    beforeSend: function (jqXHR, settings) { 
     if (settings.url.indexOf("/signalr") == -1) 
      jqXHR.setRequestHeader('Authorization', 'Basic ' + Token); 
     return true; 
    } 
}); 

Nel fare ciò, sto lasciando la classe SignalrBasicAuthFilterAttribute ad assumere la piena responsabilità per l'autorizzazione delle richieste SignalR.


Letture consigliate:

+0

L'AuthorizeHubConnection era il pezzo che mi mancava! Grazie!!! – kzfabi

1

Penso che la vera soluzione per il problema sarà assicurarsi che "Autorizzazione" faccia parte delle Intestazioni consentite (Access-Control-Allow-Headers) restituite dalla risposta signalR per la richiesta "negoziare".

È possibile registrare l'intestazione nel proprio web.config proprio come questa possibilità.

<httpProtocol> 
    <customHeaders> 
    <add name="Access-Control-Allow-Headers" value="Authorization" /> 
    </customHeaders> 
</httpProtocol>