7

Ich habe einen WebAPI mit Grund Auth gesichert, die auf die gesamte Api angelegt wird ein AuthorizationFilterAttribute verwenden. Ich habe auch SignalR Hubs auf mehreren meiner Api Controller.Mit ajaxSetup beforeSend für Basic Auth bricht SignalR Verbindung

Daneben habe ich eine Webseite, die Verwendung meiner WebAPI macht. Die Web-Seite ist vor allem in Backbone geschrieben, so, um Anrufe zu meinem gesicherten WebAPI zu machen, habe ich hinzugefügt die die folgende Jquery

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

Dies funktioniert für die Kommunikation mit meinen Api-Controller, aber das Hinzufügen des obigen Code gebrochen Verbindung zu meinem SignalR Hub, insbesondere:

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

die jqXHR.setRequestHeader() Linie stellt Verbindung meiner SignalR Hub entfernen, aber bricht die Api Anrufe.

die oben gegeben, ich etwas hacky und setzte nur die Request-Header tun könnte, wenn die Anfrage nicht zu/signalr gemacht wird, aber das fühlt sich einfach schmutzig ...

Gibt es einen sauberen Weg, um dies?

Mache ich gerade etwas albern? Ist noch jemand hineingerannt?

Antwort

7

Was ich nicht vor erwähnen ist, dass ich eine DelegatingHandler haben, die die richtigen Header auf jede Anfrage zu meinem WebAPI kommen in zurückschickt. Dies funktioniert perfekt für alle Anfragen an meine WebApi, aber ich habe fälschlicherweise angenommen, dass dies auch für SignalR-Anfragen gelten würde.

Als SignalR auf verschiedenen Transportmethoden beruht, ist es nicht sinnvoll erscheinen ich Zugriff auf Authorization Header in erster Linie müssen davon ausgehen - sie sind keine Voraussetzung aller WebSockets Implementierungen zum Beispiel (see here)

Meine aktuelle Lösung wurde zur Verwendung SignalR des HubPipeline (detailed here) zu machen. Mit diesem, glaube ich, dass ich die Grund Auth-Anmeldeinformationen in einem Query-String übergeben und schreiben kann ein separate Modul Berechtigung für die SignalR Anfragen für den Umgang:


Vorbei an den Query-String

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

der Filter

public class SignalrBasicAuthFilterAttribute: Attribute, IAuthorizeHubConnection { 

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

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

     return true; 
    } 

} 

Registrieren von t Filtern er

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

Zusätzlich ...

Beachten Sie, dass, weil es keine zuverlässige Annahme ist ein Authorization-Header mit SignalR Anforderungen zu senden, für den oben genannten Gründen, ich nur noch meine $ .ajaxSetup Filterung bin zu nicht-SignalR Anfragen betreffen:

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

Dabei lasse ich die SignalRBasicAuthFilterAttribute-Klasse die volle Verantwortung für die Autorisierung von SignalR-Anfragen übernehmen.


Weiterführende Literatur:

+0

Die AuthorizeHubConnection war das Stück, das ich fehlte! Vielen Dank!!! – kzfabi

1

Ich denke, die wirkliche Lösung für das Problem wird sicherstellen, dass "Authorization" Teil der zulässigen Header (Access-Control-Allow-Header) von der SignalR-Antwort für "verhandeln" Anfrage zurückgegeben wird.

Sie könnten den Header in Ihrer web.config wie diese Möglichkeit registrieren.

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