JWT JS Sample
This commit is contained in:
parent
18a65496b7
commit
a4dd0cd9d7
11
SignalR.sln
11
SignalR.sln
|
|
@ -1,6 +1,6 @@
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 15
|
# Visual Studio 15
|
||||||
VisualStudioVersion = 15.0.26919.1
|
VisualStudioVersion = 15.0.26923.0
|
||||||
MinimumVisualStudioVersion = 15.0.26730.03
|
MinimumVisualStudioVersion = 15.0.26730.03
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{DA69F624-5398-4884-87E4-B816698CDE65}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{DA69F624-5398-4884-87E4-B816698CDE65}"
|
||||||
ProjectSection(SolutionItems) = preProject
|
ProjectSection(SolutionItems) = preProject
|
||||||
|
|
@ -87,7 +87,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "benchmarks", "benchmarks",
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.SignalR.Client", "src\Microsoft.AspNetCore.SignalR.Client\Microsoft.AspNetCore.SignalR.Client.csproj", "{BE982591-F4BB-42D9-ABD4-A5D44C65971E}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.SignalR.Client", "src\Microsoft.AspNetCore.SignalR.Client\Microsoft.AspNetCore.SignalR.Client.csproj", "{BE982591-F4BB-42D9-ABD4-A5D44C65971E}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.SignalR.Redis.Tests", "test\Microsoft.AspNetCore.SignalR.Redis.Tests\Microsoft.AspNetCore.SignalR.Redis.Tests.csproj", "{0B083AE6-86CA-4E0B-AE02-59154D1FD005}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.SignalR.Redis.Tests", "test\Microsoft.AspNetCore.SignalR.Redis.Tests\Microsoft.AspNetCore.SignalR.Redis.Tests.csproj", "{0B083AE6-86CA-4E0B-AE02-59154D1FD005}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JwtSample", "samples\JwtSample\JwtSample.csproj", "{6A7491D3-3C97-49BD-A71C-433AED657F30}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
|
@ -195,6 +197,10 @@ Global
|
||||||
{0B083AE6-86CA-4E0B-AE02-59154D1FD005}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{0B083AE6-86CA-4E0B-AE02-59154D1FD005}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{0B083AE6-86CA-4E0B-AE02-59154D1FD005}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{0B083AE6-86CA-4E0B-AE02-59154D1FD005}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{0B083AE6-86CA-4E0B-AE02-59154D1FD005}.Release|Any CPU.Build.0 = Release|Any CPU
|
{0B083AE6-86CA-4E0B-AE02-59154D1FD005}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{6A7491D3-3C97-49BD-A71C-433AED657F30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{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
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
@ -226,6 +232,7 @@ Global
|
||||||
{E081EE41-D95F-4AD2-BC0B-4B562C0A2A47} = {DA69F624-5398-4884-87E4-B816698CDE65}
|
{E081EE41-D95F-4AD2-BC0B-4B562C0A2A47} = {DA69F624-5398-4884-87E4-B816698CDE65}
|
||||||
{BE982591-F4BB-42D9-ABD4-A5D44C65971E} = {DA69F624-5398-4884-87E4-B816698CDE65}
|
{BE982591-F4BB-42D9-ABD4-A5D44C65971E} = {DA69F624-5398-4884-87E4-B816698CDE65}
|
||||||
{0B083AE6-86CA-4E0B-AE02-59154D1FD005} = {6A35B453-52EC-48AF-89CA-D4A69800F131}
|
{0B083AE6-86CA-4E0B-AE02-59154D1FD005} = {6A35B453-52EC-48AF-89CA-D4A69800F131}
|
||||||
|
{6A7491D3-3C97-49BD-A71C-433AED657F30} = {C4BC9889-B49F-41B6-806B-F84941B2549B}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {7945A4E4-ACDB-4F6E-95CA-6AC6E7C2CD59}
|
SolutionGuid = {7945A4E4-ACDB-4F6E-95CA-6AC6E7C2CD59}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.SignalR.Internal;
|
using Microsoft.AspNetCore.SignalR.Internal;
|
||||||
using Microsoft.AspNetCore.Sockets;
|
using Microsoft.AspNetCore.Sockets;
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,7 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
|
@ -16,7 +12,6 @@ namespace Microsoft.AspNetCore.SignalR.Test.Server
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
var host = new WebHostBuilder()
|
var host = new WebHostBuilder()
|
||||||
.UseSetting(WebHostDefaults.PreventHostingStartupKey, "true") // Work around https://github.com/aspnet/Hosting/issues/1075
|
|
||||||
.ConfigureLogging(factory =>
|
.ConfigureLogging(factory =>
|
||||||
{
|
{
|
||||||
factory.AddConsole();
|
factory.AddConsole();
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.SignalR;
|
||||||
|
|
||||||
|
namespace JwtSample
|
||||||
|
{
|
||||||
|
[Authorize(JwtBearerDefaults.AuthenticationScheme)]
|
||||||
|
public class Broadcaster : Hub
|
||||||
|
{
|
||||||
|
public Task Broadcast(string sender, string message) =>
|
||||||
|
Clients.All.InvokeAsync("Message", sender, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="wwwroot\" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR\Microsoft.AspNetCore.SignalR.csproj" />
|
||||||
|
<ProjectReference Include="..\..\client-ts\Microsoft.AspNetCore.SignalR.Client.TS\Microsoft.AspNetCore.SignalR.Client.TS.csproj" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="$(MicrosoftAspNetCoreAuthenticationJwtBearerPackageVersion)" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="$(MicrosoftAspNetCoreDiagnosticsPackageVersion)" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="$(MicrosoftAspNetCoreHostingPackageVersion)" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="$(MicrosoftAspNetCoreServerIISIntegrationPackageVersion)" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="$(MicrosoftAspNetCoreServerKestrelPackageVersion)" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="$(MicrosoftAspNetCoreStaticFilesPackageVersion)" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(MicrosoftExtensionsLoggingConsolePackageVersion)" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="$(MicrosoftExtensionsLoggingDebugPackageVersion)" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<Target Name="CopyTSClient" BeforeTargets="AfterBuild">
|
||||||
|
<Copy SourceFiles="$(MSBuildThisFileDirectory)..\..\client-ts\dist\browser\signalr-client.js" DestinationFolder="$(MSBuildThisFileDirectory)wwwroot\lib\signalr-client" />
|
||||||
|
</Target>
|
||||||
|
</Project>
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace JwtSample
|
||||||
|
{
|
||||||
|
public class Program
|
||||||
|
{
|
||||||
|
public static void Main(string[] args)
|
||||||
|
{
|
||||||
|
new WebHostBuilder()
|
||||||
|
.ConfigureLogging(factory =>
|
||||||
|
{
|
||||||
|
factory.AddConsole();
|
||||||
|
factory.AddFilter("Console", level => level >= LogLevel.Information);
|
||||||
|
factory.AddDebug();
|
||||||
|
})
|
||||||
|
.UseKestrel()
|
||||||
|
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||||
|
.UseIISIntegration()
|
||||||
|
.UseStartup<Startup>()
|
||||||
|
.Build()
|
||||||
|
.Run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"iisSettings": {
|
||||||
|
"windowsAuthentication": false,
|
||||||
|
"anonymousAuthentication": true,
|
||||||
|
"iisExpress": {
|
||||||
|
"applicationUrl": "http://localhost:54542/",
|
||||||
|
"sslPort": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"profiles": {
|
||||||
|
"IIS Express": {
|
||||||
|
"commandName": "IISExpress",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"JwtSample": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
},
|
||||||
|
"applicationUrl": "http://localhost:54543/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,83 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Routing;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
|
||||||
|
namespace JwtSample
|
||||||
|
{
|
||||||
|
public class Startup
|
||||||
|
{
|
||||||
|
private readonly SymmetricSecurityKey SecurityKey = new SymmetricSecurityKey(Guid.NewGuid().ToByteArray());
|
||||||
|
private readonly JwtSecurityTokenHandler JwtTokenHandler = new JwtSecurityTokenHandler();
|
||||||
|
|
||||||
|
public void ConfigureServices(IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddSignalR();
|
||||||
|
services.AddAuthorization(options =>
|
||||||
|
{
|
||||||
|
options.AddPolicy(JwtBearerDefaults.AuthenticationScheme, policy =>
|
||||||
|
{
|
||||||
|
policy.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme);
|
||||||
|
policy.RequireClaim(ClaimTypes.NameIdentifier);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
||||||
|
.AddJwtBearer(options =>
|
||||||
|
{
|
||||||
|
options.TokenValidationParameters =
|
||||||
|
new TokenValidationParameters
|
||||||
|
{
|
||||||
|
ValidateAudience = false,
|
||||||
|
ValidateIssuer = false,
|
||||||
|
ValidateActor = false,
|
||||||
|
ValidateLifetime = true,
|
||||||
|
IssuerSigningKey = SecurityKey
|
||||||
|
};
|
||||||
|
|
||||||
|
options.Events = new JwtBearerEvents
|
||||||
|
{
|
||||||
|
OnMessageReceived = context =>
|
||||||
|
{
|
||||||
|
var signalRTokenHeader = context.Request.Query["signalRTokenHeader"];
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(signalRTokenHeader) &&
|
||||||
|
(context.HttpContext.WebSockets.IsWebSocketRequest || context.Request.Headers["Accept"] == "text/event-stream"))
|
||||||
|
{
|
||||||
|
context.Token = context.Request.Query["signalRTokenHeader"];
|
||||||
|
}
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
|
||||||
|
{
|
||||||
|
app.UseFileServer();
|
||||||
|
app.UseSignalR(options => options.MapHub<Broadcaster>("broadcast"));
|
||||||
|
|
||||||
|
var routeBuilder = new RouteBuilder(app);
|
||||||
|
routeBuilder.MapGet("generatetoken", c => c.Response.WriteAsync(GenerateToken(c)));
|
||||||
|
app.UseRouter(routeBuilder.Build());
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GenerateToken(HttpContext httpContext)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
return JwtTokenHandler.WriteToken(token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,104 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>SignalR JWT Sample</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="log">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
<script type="text/javascript" src="lib/signalr-client/signalr-client.js"></script>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
function createLog(clientId) {
|
||||||
|
var log = document.getElementById('log');
|
||||||
|
var ul = document.createElement('ul');
|
||||||
|
ul.id = 'log' + clientId;
|
||||||
|
log.appendChild(ul);
|
||||||
|
}
|
||||||
|
|
||||||
|
function appendLog(clientId, entry) {
|
||||||
|
var listId = document.getElementById('log' + clientId);
|
||||||
|
if (listId.children.length > 11) {
|
||||||
|
listId.removeChild(listId.children[1]);
|
||||||
|
}
|
||||||
|
var child = document.createElement('li');
|
||||||
|
child.innerText = entry;
|
||||||
|
listId.appendChild(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
function get(url) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
var xhr = new XMLHttpRequest();
|
||||||
|
xhr.open('GET', url, true);
|
||||||
|
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
|
||||||
|
xhr.send();
|
||||||
|
xhr.onload = () => {
|
||||||
|
if (xhr.status >= 200 && xhr.status < 300) {
|
||||||
|
resolve(xhr.response || xhr.responseText);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
reject(new Error(xhr.statusText));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
xhr.onerror = () => {
|
||||||
|
reject(new Error(xhr.statusText));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var tokens = {};
|
||||||
|
|
||||||
|
function refreshToken(clientId) {
|
||||||
|
var tokenUrl = 'http://' + document.location.host + '/generatetoken?user=' + clientId;
|
||||||
|
return get(tokenUrl)
|
||||||
|
.then(function (token) {
|
||||||
|
tokens[clientId] = token;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function runConnection(clientId, transportType) {
|
||||||
|
var connection;
|
||||||
|
|
||||||
|
refreshToken(clientId)
|
||||||
|
.then(function () {
|
||||||
|
var options = {
|
||||||
|
transport: transportType,
|
||||||
|
jwtBearer: function () { return tokens[clientId]; }
|
||||||
|
};
|
||||||
|
|
||||||
|
connection = new signalR.HubConnection('/broadcast', options);
|
||||||
|
connection.on('Message', function (from, message) {
|
||||||
|
appendLog(clientId, from + ': ' + message);
|
||||||
|
});
|
||||||
|
return connection.start();
|
||||||
|
})
|
||||||
|
.then(function () {
|
||||||
|
appendLog(clientId, 'user ' + clientId + ' connected');
|
||||||
|
setInterval(function () {
|
||||||
|
appendLog(clientId, 'Refreshing token');
|
||||||
|
refreshToken(clientId);
|
||||||
|
}, 20000);
|
||||||
|
setTimeout(function sendMessage() {
|
||||||
|
connection.send('broadcast', clientId, 'Hello at ' + new Date().toLocaleString());
|
||||||
|
var timeout = 2000 + Math.random() * 4000;
|
||||||
|
setTimeout(sendMessage, timeout);
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch(function (e) {
|
||||||
|
appendLog(clientId, 'Could not start connection');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[signalR.TransportType.WebSockets, signalR.TransportType.ServerSentEvents, signalR.TransportType.LongPolling].forEach(function(transportType) {
|
||||||
|
var clientId = 'browser ' + signalR.TransportType[transportType];
|
||||||
|
createLog(clientId);
|
||||||
|
appendLog(clientId, 'Log for user: ' + clientId);
|
||||||
|
runConnection(clientId, transportType);
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
Loading…
Reference in New Issue