[release/3.1] Pass access token as query string when running SignalR in the browser (#20466)

* Pass access token as query string when running SignalR in the browser

* WEBASSEMBLY -> BROWSER
This commit is contained in:
William Godbe 2020-04-14 12:59:06 -07:00 committed by GitHub
parent 8dc0b49ea7
commit 01429973ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 45 additions and 1 deletions

View File

@ -66,6 +66,9 @@ namespace Microsoft.AspNetCore.Http.Connections.Client
private static readonly Action<ILogger, HttpTransportType, Exception> _transportStarted =
LoggerMessage.Define<HttpTransportType>(LogLevel.Debug, new EventId(18, "TransportStarted"), "Transport '{Transport}' started.");
private static readonly Action<ILogger, Exception> _serverSentEventsNotSupportedByBrowser =
LoggerMessage.Define(LogLevel.Debug, new EventId(19, "ServerSentEventsNotSupportedByBrowser"), "Skipping ServerSentEvents because they are not supported by the browser.");
public static void Starting(ILogger logger)
{
_starting(logger, null);
@ -167,6 +170,11 @@ namespace Microsoft.AspNetCore.Http.Connections.Client
{
_transportStarted(logger, transportType, null);
}
public static void ServerSentEventsNotSupportedByBrowser(ILogger logger)
{
_serverSentEventsNotSupportedByBrowser(logger, null);
}
}
}
}

View File

@ -37,6 +37,7 @@ namespace Microsoft.AspNetCore.Http.Connections.Client
private bool _started;
private bool _disposed;
private bool _hasInherentKeepAlive;
private bool _isRunningInBrowser;
private readonly HttpClient _httpClient;
private readonly HttpConnectionOptions _httpConnectionOptions;
@ -150,6 +151,14 @@ namespace Microsoft.AspNetCore.Http.Connections.Client
_httpClient = CreateHttpClient();
}
_isRunningInBrowser = Utils.IsRunningInBrowser();
if (httpConnectionOptions.Transports == HttpTransportType.ServerSentEvents && _isRunningInBrowser)
{
throw new ArgumentException("ServerSentEvents can not be the only transport specified when running in the browser.", nameof(httpConnectionOptions));
}
_transportFactory = new DefaultTransportFactory(httpConnectionOptions.Transports, _loggerFactory, _httpClient, httpConnectionOptions, GetAccessTokenAsync);
_logScope = new ConnectionLogScope();
@ -365,6 +374,13 @@ namespace Microsoft.AspNetCore.Http.Connections.Client
continue;
}
if (transportType == HttpTransportType.ServerSentEvents && _isRunningInBrowser)
{
Log.ServerSentEventsNotSupportedByBrowser(_logger);
transportExceptions.Add(new TransportFailedException("ServerSentEvents", "The transport is not supported in the browser."));
continue;
}
try
{
if ((transportType & _httpConnectionOptions.Transports) == 0)

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Runtime.InteropServices;
namespace Microsoft.AspNetCore.Http.Connections.Client.Internal
{
@ -41,5 +42,10 @@ namespace Microsoft.AspNetCore.Http.Connections.Client.Internal
builder.Query = newQueryString;
return builder.Uri;
}
internal static bool IsRunningInBrowser()
{
return RuntimeInformation.IsOSPlatform(OSPlatform.Create("BROWSER"));
}
}
}

View File

@ -6,6 +6,7 @@ using System.Diagnostics;
using System.IO.Pipelines;
using System.Net.WebSockets;
using System.Runtime.InteropServices;
using System.Text.Encodings.Web;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Connections;
@ -23,6 +24,7 @@ namespace Microsoft.AspNetCore.Http.Connections.Client.Internal
private readonly ILogger _logger;
private readonly TimeSpan _closeTimeout;
private volatile bool _aborted;
private bool _isRunningInBrowser;
private IDuplexPipe _transport;
@ -87,6 +89,8 @@ namespace Microsoft.AspNetCore.Http.Connections.Client.Internal
// Ignore the HttpConnectionOptions access token provider. We were given an updated delegate from the HttpConnection.
_accessTokenProvider = accessTokenProvider;
_isRunningInBrowser = Utils.IsRunningInBrowser();
}
public async Task StartAsync(Uri url, TransferFormat transferFormat, CancellationToken cancellationToken = default)
@ -113,7 +117,17 @@ namespace Microsoft.AspNetCore.Http.Connections.Client.Internal
var accessToken = await _accessTokenProvider();
if (!string.IsNullOrEmpty(accessToken))
{
_webSocket.Options.SetRequestHeader("Authorization", $"Bearer {accessToken}");
// We can't use request headers in the browser, so instead append the token as a query string in that case
if (_isRunningInBrowser)
{
var accessTokenEncoded = UrlEncoder.Default.Encode(accessToken);
accessTokenEncoded = "access_token=" + accessTokenEncoded;
resolvedUrl = Utils.AppendQueryString(resolvedUrl, accessTokenEncoded);
}
else
{
_webSocket.Options.SetRequestHeader("Authorization", $"Bearer {accessToken}");
}
}
}