Skip to content

Commit 0142997

Browse files
authored
[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
1 parent 8dc0b49 commit 0142997

File tree

4 files changed

+45
-1
lines changed

4 files changed

+45
-1
lines changed

src/SignalR/clients/csharp/Http.Connections.Client/src/HttpConnection.Log.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ private static class Log
6666
private static readonly Action<ILogger, HttpTransportType, Exception> _transportStarted =
6767
LoggerMessage.Define<HttpTransportType>(LogLevel.Debug, new EventId(18, "TransportStarted"), "Transport '{Transport}' started.");
6868

69+
private static readonly Action<ILogger, Exception> _serverSentEventsNotSupportedByBrowser =
70+
LoggerMessage.Define(LogLevel.Debug, new EventId(19, "ServerSentEventsNotSupportedByBrowser"), "Skipping ServerSentEvents because they are not supported by the browser.");
71+
6972
public static void Starting(ILogger logger)
7073
{
7174
_starting(logger, null);
@@ -167,6 +170,11 @@ public static void TransportStarted(ILogger logger, HttpTransportType transportT
167170
{
168171
_transportStarted(logger, transportType, null);
169172
}
173+
174+
public static void ServerSentEventsNotSupportedByBrowser(ILogger logger)
175+
{
176+
_serverSentEventsNotSupportedByBrowser(logger, null);
177+
}
170178
}
171179
}
172180
}

src/SignalR/clients/csharp/Http.Connections.Client/src/HttpConnection.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ public partial class HttpConnection : ConnectionContext, IConnectionInherentKeep
3737
private bool _started;
3838
private bool _disposed;
3939
private bool _hasInherentKeepAlive;
40+
private bool _isRunningInBrowser;
4041

4142
private readonly HttpClient _httpClient;
4243
private readonly HttpConnectionOptions _httpConnectionOptions;
@@ -150,6 +151,14 @@ public HttpConnection(HttpConnectionOptions httpConnectionOptions, ILoggerFactor
150151
_httpClient = CreateHttpClient();
151152
}
152153

154+
_isRunningInBrowser = Utils.IsRunningInBrowser();
155+
156+
157+
if (httpConnectionOptions.Transports == HttpTransportType.ServerSentEvents && _isRunningInBrowser)
158+
{
159+
throw new ArgumentException("ServerSentEvents can not be the only transport specified when running in the browser.", nameof(httpConnectionOptions));
160+
}
161+
153162
_transportFactory = new DefaultTransportFactory(httpConnectionOptions.Transports, _loggerFactory, _httpClient, httpConnectionOptions, GetAccessTokenAsync);
154163
_logScope = new ConnectionLogScope();
155164

@@ -365,6 +374,13 @@ private async Task SelectAndStartTransport(TransferFormat transferFormat, Cancel
365374
continue;
366375
}
367376

377+
if (transportType == HttpTransportType.ServerSentEvents && _isRunningInBrowser)
378+
{
379+
Log.ServerSentEventsNotSupportedByBrowser(_logger);
380+
transportExceptions.Add(new TransportFailedException("ServerSentEvents", "The transport is not supported in the browser."));
381+
continue;
382+
}
383+
368384
try
369385
{
370386
if ((transportType & _httpConnectionOptions.Transports) == 0)

src/SignalR/clients/csharp/Http.Connections.Client/src/Internal/Utils.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
5+
using System.Runtime.InteropServices;
56

67
namespace Microsoft.AspNetCore.Http.Connections.Client.Internal
78
{
@@ -41,5 +42,10 @@ internal static Uri AppendQueryString(Uri url, string qs)
4142
builder.Query = newQueryString;
4243
return builder.Uri;
4344
}
45+
46+
internal static bool IsRunningInBrowser()
47+
{
48+
return RuntimeInformation.IsOSPlatform(OSPlatform.Create("BROWSER"));
49+
}
4450
}
4551
}

src/SignalR/clients/csharp/Http.Connections.Client/src/Internal/WebSocketsTransport.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.IO.Pipelines;
77
using System.Net.WebSockets;
88
using System.Runtime.InteropServices;
9+
using System.Text.Encodings.Web;
910
using System.Threading;
1011
using System.Threading.Tasks;
1112
using Microsoft.AspNetCore.Connections;
@@ -23,6 +24,7 @@ internal partial class WebSocketsTransport : ITransport
2324
private readonly ILogger _logger;
2425
private readonly TimeSpan _closeTimeout;
2526
private volatile bool _aborted;
27+
private bool _isRunningInBrowser;
2628

2729
private IDuplexPipe _transport;
2830

@@ -87,6 +89,8 @@ public WebSocketsTransport(HttpConnectionOptions httpConnectionOptions, ILoggerF
8789

8890
// Ignore the HttpConnectionOptions access token provider. We were given an updated delegate from the HttpConnection.
8991
_accessTokenProvider = accessTokenProvider;
92+
93+
_isRunningInBrowser = Utils.IsRunningInBrowser();
9094
}
9195

9296
public async Task StartAsync(Uri url, TransferFormat transferFormat, CancellationToken cancellationToken = default)
@@ -113,7 +117,17 @@ public async Task StartAsync(Uri url, TransferFormat transferFormat, Cancellatio
113117
var accessToken = await _accessTokenProvider();
114118
if (!string.IsNullOrEmpty(accessToken))
115119
{
116-
_webSocket.Options.SetRequestHeader("Authorization", $"Bearer {accessToken}");
120+
// We can't use request headers in the browser, so instead append the token as a query string in that case
121+
if (_isRunningInBrowser)
122+
{
123+
var accessTokenEncoded = UrlEncoder.Default.Encode(accessToken);
124+
accessTokenEncoded = "access_token=" + accessTokenEncoded;
125+
resolvedUrl = Utils.AppendQueryString(resolvedUrl, accessTokenEncoded);
126+
}
127+
else
128+
{
129+
_webSocket.Options.SetRequestHeader("Authorization", $"Bearer {accessToken}");
130+
}
117131
}
118132
}
119133

0 commit comments

Comments
 (0)