dotnet / dotnet/AspNetCore.Docs

Better SignalR documentation for authentication

Open
#23,446 6 comments 1 reaction 0 assignees View on GitHub
doc-idea SignalR
Dominant language
C#
Stars
13.1k
Forks
24.6k
Avg merge
1d 3h
Merged PRs (30d)
97

Description

Are there any `working` code samples for net5.0 or net6.0 on how to authenticate users using Identity and tokens?

I have a working tutorial without authentication [Use ASP.NET Core SignalR with Blazor](https://docs.microsoft.com/en-us/aspnet/core/tutorials/signalr-blazor?view=aspnetcore-6.0&tabs=visual-studio&pivots=server)

The steps for authentication and authorization have code samples but seem incomplete [Authentication and authorization in ASP.NET Core SignalR](https://docs.microsoft.com/en-us/aspnet/core/signalr/authn-and-authz?view=aspnetcore-6.0)

How is the variable `_myAccessToken` set here?
```
var connection = new HubConnectionBuilder()
.WithUrl("https://example.com/chathub", options =>
{
options.AccessTokenProvider = () => Task.FromResult(_myAccessToken);
})
.Build();
```

For Built-in JWT authentication what goes here `options.Authority = /* TODO: Insert Authority URL here */;`?

If I add `[Authorize]` to the hub I would expect I can only send messages if I login, but I get an error on the client `System.Net.Http.HttpRequestException HResult=0x80131500 Message=Response status code does not indicate success: 401 (Unauthorized).`

It looks like I need to add a token to the client but I cannot work out how from the docs. Can anyone help?
```

[Authorize]
public class MessageHub : Hub
{
public async Task SendMessage(string user, string message)
{
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
}
```

TestMessageHub.razor:
```
@page "/testmessagehub"
@using Microsoft.AspNetCore.SignalR.Client
@inject NavigationManager NavigationManager
@implements IAsyncDisposable



User:





Message:



Send



    @foreach (var message in messages)
    {
  • @message

  • }

@code {
private HubConnection hubConnection = null!;
private List messages = new List();
private string userInput = null!;
private string messageInput = null!;

protected override async Task OnInitializedAsync()
{

hubConnection = new HubConnectionBuilder()
.WithUrl(NavigationManager.ToAbsoluteUri("/messagehub"))
.Build();

hubConnection.On("ReceiveMessage", (user, message) =>
{
var encodedMsg = $"{user}: {message}";
messages.Add(encodedMsg);
StateHasChanged();
});

await hubConnection.StartAsync();
}

async Task Send() =>
await hubConnection.SendAsync("SendMessage", userInput, messageInput);

public bool IsConnected =>
hubConnection.State == HubConnectionState.Connected;

public async ValueTask DisposeAsync()
{
if (hubConnection is not null)
{
await hubConnection.DisposeAsync();
}
}
}
```

Program.cs:
```
using Test.Areas.Identity;
using Test.Data;
using Test.Hubs;
using Test.Services.Mail;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.ResponseCompression;
using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext(options =>
options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services.AddIdentity(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores()
.AddTokenProvider>(TokenOptions.DefaultProvider)
.AddDefaultUI();

builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddScoped>();
builder.Services.AddSingleton();

builder.Services.Configure(o => o.TokenLifespan = TimeSpan.FromHours(24)); // Default is one day anyway but set incase later versions change
builder.Services.Configure(builder.Configuration.GetSection("EMailSettings"));
builder.Services.AddTransient();

builder.Services.AddResponseCompression(opts =>
{
opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(new[] { "application/octet-stream" });
});

var app = builder.Build();

app.UseResponseCompression();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles();

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();
app.MapBlazorHub();
app.MapHub("/messagehub");
app.MapFallbackToPage("/_Host");

app.Run();
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.