From 4394b57143ad0517333ffbe88848fbb68264a614 Mon Sep 17 00:00:00 2001 From: Pawel Kadluczka Date: Thu, 16 Nov 2017 17:05:55 -0800 Subject: [PATCH] JWT C# Sample --- SignalR.sln | 7 ++ .../JwtClientSample/JwtClientSample.csproj | 14 ++++ samples/JwtClientSample/Program.cs | 80 +++++++++++++++++++ samples/JwtSample/Startup.cs | 3 +- .../Startup.cs | 1 - 5 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 samples/JwtClientSample/JwtClientSample.csproj create mode 100644 samples/JwtClientSample/Program.cs diff --git a/SignalR.sln b/SignalR.sln index 2456b41517..c9f1d748fd 100644 --- a/SignalR.sln +++ b/SignalR.sln @@ -91,6 +91,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Signal EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JwtSample", "samples\JwtSample\JwtSample.csproj", "{6A7491D3-3C97-49BD-A71C-433AED657F30}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JwtClientSample", "samples\JwtClientSample\JwtClientSample.csproj", "{1A953296-E869-4DE2-A693-FD5FCDE27057}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -201,6 +203,10 @@ Global {6A7491D3-3C97-49BD-A71C-433AED657F30}.Debug|Any CPU.Build.0 = Debug|Any CPU {6A7491D3-3C97-49BD-A71C-433AED657F30}.Release|Any CPU.ActiveCfg = Release|Any CPU {6A7491D3-3C97-49BD-A71C-433AED657F30}.Release|Any CPU.Build.0 = Release|Any CPU + {1A953296-E869-4DE2-A693-FD5FCDE27057}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1A953296-E869-4DE2-A693-FD5FCDE27057}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1A953296-E869-4DE2-A693-FD5FCDE27057}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1A953296-E869-4DE2-A693-FD5FCDE27057}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -233,6 +239,7 @@ Global {BE982591-F4BB-42D9-ABD4-A5D44C65971E} = {DA69F624-5398-4884-87E4-B816698CDE65} {0B083AE6-86CA-4E0B-AE02-59154D1FD005} = {6A35B453-52EC-48AF-89CA-D4A69800F131} {6A7491D3-3C97-49BD-A71C-433AED657F30} = {C4BC9889-B49F-41B6-806B-F84941B2549B} + {1A953296-E869-4DE2-A693-FD5FCDE27057} = {C4BC9889-B49F-41B6-806B-F84941B2549B} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {7945A4E4-ACDB-4F6E-95CA-6AC6E7C2CD59} diff --git a/samples/JwtClientSample/JwtClientSample.csproj b/samples/JwtClientSample/JwtClientSample.csproj new file mode 100644 index 0000000000..c6aea92edb --- /dev/null +++ b/samples/JwtClientSample/JwtClientSample.csproj @@ -0,0 +1,14 @@ + + + + netcoreapp2.0 + + false + Exe + + + + + + + diff --git a/samples/JwtClientSample/Program.cs b/samples/JwtClientSample/Program.cs new file mode 100644 index 0000000000..8358f9c3a3 --- /dev/null +++ b/samples/JwtClientSample/Program.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Concurrent; +using System.Net.Http; +using System.Threading.Tasks; +using Microsoft.AspNetCore.SignalR.Client; +using Microsoft.AspNetCore.Sockets; + +namespace JwtClientSample +{ + class Program + { + static async Task Main(string[] args) + { + var app = new Program(); + await Task.WhenAll( + app.RunConnection(TransportType.WebSockets), + app.RunConnection(TransportType.ServerSentEvents), + app.RunConnection(TransportType.LongPolling)); + } + + private const string ServerUrl = "http://localhost:54543"; + + private readonly ConcurrentDictionary _tokens = new ConcurrentDictionary(); + private readonly Random _random = new Random(); + + private async Task RunConnection(TransportType transportType) + { + var userId = "C#" + transportType.ToString(); + _tokens[userId] = await GetJwtToken(userId); + + var hubConnection = new HubConnectionBuilder() + .WithUrl(ServerUrl + "/broadcast") + .WithTransport(transportType) + .WithJwtBearer(() => _tokens[userId]) + .Build(); + + hubConnection.On("Message", (sender, message) => Console.WriteLine($"[{userId}] {sender}: {message}")); + await hubConnection.StartAsync(); + Console.WriteLine($"[{userId}] Connection Started"); + + var ticks = 0; + var nextMsgAt = 3; + + try + { + while (!hubConnection.Closed.IsCompleted) + { + await Task.Delay(1000); + ticks++; + if (ticks % 15 == 0) + { + // no need to refresh the token for websockets + if (transportType != TransportType.WebSockets) + { + _tokens[userId] = await GetJwtToken(userId); + Console.WriteLine($"[{userId}] Token refreshed"); + } + } + + if (ticks % nextMsgAt == 0) + { + await hubConnection.SendAsync("Broadcast", userId, $"Hello at {DateTime.Now.ToString()}"); + nextMsgAt = _random.Next(2, 5); + } + } + } + catch (Exception ex) + { + Console.WriteLine($"[{userId}] Connection terminated with error: {ex}"); + } + } + + private async Task GetJwtToken(string userId) + { + var httpResponse = await new HttpClient().GetAsync(ServerUrl + $"/generatetoken?user={userId}"); + httpResponse.EnsureSuccessStatusCode(); + return await httpResponse.Content.ReadAsStringAsync(); + } + } +} diff --git a/samples/JwtSample/Startup.cs b/samples/JwtSample/Startup.cs index 46f9598cfb..63887aa920 100644 --- a/samples/JwtSample/Startup.cs +++ b/samples/JwtSample/Startup.cs @@ -38,6 +38,7 @@ namespace JwtSample options.TokenValidationParameters = new TokenValidationParameters { + LifetimeValidator = (before, expires, token, parameters) => expires > DateTime.UtcNow, ValidateAudience = false, ValidateIssuer = false, ValidateActor = false, @@ -76,7 +77,7 @@ namespace JwtSample { var claims = new[] { new Claim(ClaimTypes.NameIdentifier, httpContext.Request.Query["user"]) }; var credentials = new SigningCredentials(SecurityKey, SecurityAlgorithms.HmacSha256); - var token = new JwtSecurityToken("SignalRTestServer", "SignalRTests", claims, expires: DateTime.Now.AddSeconds(30), signingCredentials: credentials); + var token = new JwtSecurityToken("SignalRTestServer", "SignalRTests", claims, expires: DateTime.UtcNow.AddSeconds(30), signingCredentials: credentials); return JwtTokenHandler.WriteToken(token); } } diff --git a/test/Microsoft.AspNetCore.SignalR.Client.FunctionalTests/Startup.cs b/test/Microsoft.AspNetCore.SignalR.Client.FunctionalTests/Startup.cs index e0d9d09e5e..fe5aa3cdc8 100644 --- a/test/Microsoft.AspNetCore.SignalR.Client.FunctionalTests/Startup.cs +++ b/test/Microsoft.AspNetCore.SignalR.Client.FunctionalTests/Startup.cs @@ -63,7 +63,6 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests return; } }); - } private string GenerateJwtToken()