add claimtypes.email provider to auth sample & article (#10691)

* finished #6925

* augmented per @BrennanConroy

* fixed css link

* added method to hub

* added code from sample to file

* fixed user sample

* removed the email version of this sample

* removed last mention of the customization

* Minor edits

* added (and tested) claimtypes.email-supporting identity approach

* referencing code in sample instead of hard-typed

* fixed a dumb thing

* implemented all changes suggested by @tdykstra

* fixed suggestions from @scottaddie

* updated metadata

* Update ms.date

* tweaks implemented per @BrennanConroy

* Update heading
pull/10751/head
Brady Gaster 2019-02-01 14:03:44 -08:00 committed by Scott Addie
parent f3b641a099
commit e3c3b8d125
7 changed files with 58 additions and 19 deletions

View File

@ -3,9 +3,9 @@ title: Authentication and authorization in ASP.NET Core SignalR
author: bradygaster
description: Learn how to use authentication and authorization in ASP.NET Core SignalR.
monikerRange: '>= aspnetcore-2.1'
ms.author: anurse
ms.author: bradyg
ms.custom: mvc
ms.date: 06/29/2018
ms.date: 01/31/2019
uid: signalr/authn-and-authz
---
@ -63,22 +63,14 @@ If [Windows authentication](xref:security/authentication/windowsauth) is configu
Add a new class that implements `IUserIdProvider` and retrieve one of the claims from the user to use as the identifier. For example, to use the "Name" claim (which is the Windows username in the form `[Domain]\[Username]`), create the following class:
```csharp
public class NameUserIdProvider : IUserIdProvider
{
public string GetUserId(HubConnectionContext connection)
{
return connection.User?.FindFirst(ClaimTypes.Name)?.Value;
}
}
```
[!code-csharp[Name based provider](authn-and-authz/sample/nameuseridprovider.cs?name=NameUserIdProvider)]
Rather than `ClaimTypes.Name`, you can use any value from the `User` (such as the Windows SID identifier, etc.).
> [!NOTE]
> The value you choose must be unique among all the users in your system. Otherwise, a message intended for one user could end up going to a different user.
Register this component in your `Startup.ConfigureServices` method **after** the call to `.AddSignalR`
Register this component in your `Startup.ConfigureServices` method.
```csharp
public void ConfigureServices(IServiceCollection services)
@ -103,6 +95,27 @@ var connection = new HubConnectionBuilder()
Windows Authentication is only supported by the browser client when using Microsoft Internet Explorer or Microsoft Edge.
### Use claims to customize identity handling
An app that authenticates users can derive SignalR user IDs from user claims. To specify how SignalR creates user IDs, implement `IUserIdProvider` and register the implementation.
The sample code demonstrates how you would use claims to select the user's email address as the identifying property.
> [!NOTE]
> The value you choose must be unique among all the users in your system. Otherwise, a message intended for one user could end up going to a different user.
[!code-csharp[Email provider](authn-and-authz/sample/EmailBasedUserIdProvider.cs?name=EmailBasedUserIdProvider)]
The account registration adds a claim with type `ClaimsTypes.Email` to the ASP.NET identity database.
[!code-csharp[Adding the email to the ASP.NET identity claims](authn-and-authz/sample/pages/account/Register.cshtml.cs?name=AddEmailClaim)]
Register this component in your `Startup.ConfigureServices`.
```csharp
services.AddSingleton<IUserIdProvider, EmailBasedUserIdProvider>();
```
## Authorize users to access hubs and hub methods
By default, all methods in a hub can be called by an unauthenticated user. In order to require authentication, apply the [Authorize](/dotnet/api/microsoft.aspnetcore.authorization.authorizeattribute) attribute to the hub:

View File

@ -0,0 +1,15 @@
using System.Security.Claims;
using Microsoft.AspNetCore.SignalR;
namespace SignalRAuthenticationSample
{
#region EmailBasedUserIdProvider
public class EmailBasedUserIdProvider : IUserIdProvider
{
public virtual string GetUserId(HubConnectionContext connection)
{
return connection.User?.FindFirst(ClaimTypes.Email)?.Value;
}
}
#endregion
}

View File

@ -2,6 +2,7 @@ using Microsoft.AspNetCore.SignalR;
namespace SignalRAuthenticationSample
{
#region NameUserIdProvider
public class NameUserIdProvider : IUserIdProvider
{
public string GetUserId(HubConnectionContext connection)
@ -9,4 +10,5 @@ namespace SignalRAuthenticationSample
return connection.User?.Identity?.Name;
}
}
#endregion
}

View File

@ -1,11 +1,11 @@
using System.ComponentModel.DataAnnotations;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
using SignalRAuthenticationSample.Data;
using SignalRAuthenticationSample.Services;
namespace SignalRAuthenticationSample.Pages.Account
{
@ -14,18 +14,15 @@ namespace SignalRAuthenticationSample.Pages.Account
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly UserManager<ApplicationUser> _userManager;
private readonly ILogger<RegisterModel> _logger;
private readonly IEmailSender _emailSender;
public RegisterModel(
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager,
ILogger<RegisterModel> logger,
IEmailSender emailSender)
ILogger<RegisterModel> logger)
{
_userManager = userManager;
_signInManager = signInManager;
_logger = logger;
_emailSender = emailSender;
}
[BindProperty]
@ -62,8 +59,14 @@ namespace SignalRAuthenticationSample.Pages.Account
ReturnUrl = returnUrl;
if (ModelState.IsValid)
{
#region AddEmailClaim
// create a new user
var user = new ApplicationUser { UserName = Input.Email, Email = Input.Email };
var result = await _userManager.CreateAsync(user, Input.Password);
// add the email claim and value for this user
await _userManager.AddClaimAsync(user, new Claim(ClaimTypes.Email, Input.Email));
#endregion
if (result.Succeeded)
{
_logger.LogInformation("User created a new account with password.");

View File

@ -13,7 +13,7 @@
<link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/css/bootstrap.min.css"
asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"
asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" />
<link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" />
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
</environment>
</head>
<body>

View File

@ -97,6 +97,12 @@ namespace SignalRAuthenticationSample
// If the Name claim isn't unique, users could receive messages
// intended for a different user!
services.AddSingleton<IUserIdProvider, NameUserIdProvider>();
// Change to use email as the user identifier for SignalR
// services.AddSingleton<IUserIdProvider, EmailBasedUserIdProvider>();
// WARNING: use *either* the NameUserIdProvider *or* the
// EmailBasedUserIdProvider, but do not use both.
}
#endregion

View File

@ -1,5 +1,5 @@
body {
padding-top: 50px;
padding-top: 80px;
padding-bottom: 20px;
}