A autenticação do SignalR falhou ao passar "Portador" pela sequência de consultas
Gostaria de habilitar a autenticação no SignalR enquanto o servidor estava hospedado no ASP.NET WebAPI, que estou usando a autenticação automática OAuth Bearer e o cliente é AngularJS.
No lado do cliente, passei originalmente o token do Bearer pelo cabeçalho HTTP e ele funciona bem com a WebAPI. Porém, como o SignalR JavsScript não suporta a adição de cabeçalhos HTTP noconnection
(é porque o WebSocket não suporta a especificação de cabeçalhos HTTP). Preciso passar o token do Bearer através da string de consulta usando o código comoself.connection.qs = { Bearer: 'xxxxxx' };
O problema está no lado da WebAPI, o meu SignalR sempre retornava 401 não autorizado.
Abaixo está o que eu fiz no lado da WebAPI.
1, eu especifiqueiOAuthBearerAuthenticationOptions.Provider
paraQueryStringEnabledOAuthBearerAuthenticationProvider
, que é uma classe que criei herdada deOAuthBearerAuthenticationProvider
que pode recuperar o token do Bearer da string de consulta. Código como abaixo.
public class QueryStringEnabledOAuthBearerAuthenticationProvider : OAuthBearerAuthenticationProvider { private readonly string _name; public QueryStringEnabledOAuthBearerAuthenticationProvider() : this(OAuthDefaults.AuthenticationType) { } public QueryStringEnabledOAuthBearerAuthenticationProvider(string name) { _name = name; } public override Task RequestToken(OAuthRequestTokenContext context) { // try to read token from base class (header) if possible base.RequestToken(context).Wait(); if (string.IsNullOrWhiteSpace(context.Token)) { // try to read token from query string var token = context.Request.Query.Get(_name); if (!string.IsNullOrWhiteSpace(token)) { context.Token = token; } } return Task.FromResult(null); } }
E registre-o como abaixo enquanto o WebAPI foi iniciado.
var options = new OAuthBearerAuthenticationOptions { AuthenticationMode = AuthenticationMode.Active, AuthenticationType = AuthenticationType, Provider = new QueryStringEnabledOAuthBearerAuthenticationProvider(), AccessTokenFormat = _accessTokenFormat, }; config.SuppressDefaultHostAuthentication(); config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType)); app.UseOAuthBearerAuthentication(options);
2, na parte SignalR, criei um atributo de autorização como abaixo. Nada mudou apenas para ser usado para adicionar um ponto de interrupção.
public class BearerAuthorizeAttribute : AuthorizeAttribute { public override bool AuthorizeHubConnection(HubDescriptor hubDescriptor, IRequest request) { return base.AuthorizeHubConnection(hubDescriptor, request); } public override bool AuthorizeHubMethodInvocation(IHubIncomingInvokerContext hubIncomingInvokerContext, bool appliesToMethod) { return base.AuthorizeHubMethodInvocation(hubIncomingInvokerContext, appliesToMethod); } }
E registrou quando o WebAPI começou também.
app.Map("/signalr", map => { // Setup the CORS middleware to run before SignalR. // By default this will allow all origins. You can // configure the set of origins and/or http verbs by // providing a cors options with a different policy. map.UseCors(CorsOptions.AllowAll); var hubConfiguration = new HubConfiguration { // You can enable JSONP by uncommenting line below. // JSONP requests are insecure but some older browsers (and some // versions of IE) require JSONP to work cross domain // EnableJSONP = true EnableJavaScriptProxies = false }; // Run the SignalR pipeline. We're not using MapSignalR // since this branch already runs under the "/signalr" // path. map.RunSignalR(hubConfiguration); // Require authentication for all hubs var authorizer = new BearerAuthorizeAttribute(); var module = new AuthorizeModule(authorizer, authorizer); GlobalHost.HubPipeline.AddModule(module); });
Eu descobri que quando o SignalR conectouQueryStringEnabledOAuthBearerAuthenticationProvider.RequestToken
foi invocado e recuperou o token do Bearer com êxito. Mas então, quando SignalRBearerAuthorizeAttribute.AuthorizeHubConnection
foi chamado o parâmetrorequest.User
ainda não autenticado. Então ele retornou 401.
Alguém pode me dar algumas idéias sobre o que eu fiz de errado, obrigado.