Skip to content

Commit 1a2fb0a

Browse files
committed
Updates
1 parent 445cdfa commit 1a2fb0a

File tree

2 files changed

+53
-44
lines changed

2 files changed

+53
-44
lines changed

aspnetcore/blazor/security/account-confirmation-and-password-recovery.md

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ The app's namespace used by the example in this article is `BlazorSample`. Updat
2424

2525
In this article, [Mailchimp's Transactional API](https://mailchimp.com/developer/transactional/api/) is used via [Mandrill.net](https://www.nuget.org/packages/Mandrill.net) to send email. We recommend using an email service to send email rather than SMTP. SMTP is difficult to configure and secure properly. Whichever email service you use, access their guidance for .NET apps, create an account, configure an API key for their service, and install any NuGet packages required.
2626

27-
Create a class to fetch the secure email API key. The example in this article uses a class named `AuthMessageSenderOptions` with a `EmailAuthKey` property to hold the key.
27+
Create a class to hold the secret email provider API key. The example in this article uses a class named `AuthMessageSenderOptions` with an `EmailAuthKey` property to hold the key.
2828

2929
`AuthMessageSenderOptions.cs`:
3030

@@ -51,7 +51,7 @@ If the project has already been initialized for the [Secret Manager tool](xref:s
5151
dotnet user-secrets init
5252
```
5353

54-
Set the key with the Secret Manager tool. In the following example, the key name is `EmailAuthKey`, and the key is represented by the `{KEY}` placeholder. In a command shell, navigate to the app's root folder and execute the following command with the API key:
54+
Set the API key with the Secret Manager tool. In the following example, the key name is `EmailAuthKey` to match `AuthMessageSenderOptions.EmailAuthKey`, and the key is represented by the `{KEY}` placeholder. Execute the following command with the API key:
5555

5656
```dotnetcli
5757
dotnet user-secrets set "EmailAuthKey" "{KEY}"
@@ -69,7 +69,7 @@ The following example is based on Mailchimp's Transactional API using [Mandrill.
6969

7070
Add the [Mandrill.net](https://www.nuget.org/packages/Mandrill.net) NuGet package to the project.
7171

72-
Add the following `EmailSender` class to implement <xref:Microsoft.AspNetCore.Identity.IEmailSender%601>. In the following example, `ApplicationUser` is a <xref:Microsoft.AspNetCore.Identity.IdentityUser>. The message HTML markup can be further customized. As long as the `message` passed to `MandrillMessage` starts with the `<` character, the Mandrill.net API assumes that the message body is composed in HTML.
72+
Add the following `EmailSender` class to implement <xref:Microsoft.AspNetCore.Identity.IEmailSender%601>. In the following example, `ApplicationUser` is an <xref:Microsoft.AspNetCore.Identity.IdentityUser>. The message HTML markup can be further customized. As long as the `message` passed to `MandrillMessage` starts with the `<` character, the Mandrill.net API assumes that the message body is composed in HTML.
7373

7474
`Components/Account/EmailSender.cs`:
7575

@@ -128,7 +128,7 @@ public class EmailSender(IOptions<AuthMessageSenderOptions> optionsAccessor,
128128
```
129129

130130
> [!NOTE]
131-
> Body content for messages might require special encoding for the email service provider. If links in the message body can't be followed, consult the service provider's documentation.
131+
> Body content for messages might require special encoding for the email service provider. If links in the message body can't be followed in the email message, consult the service provider's documentation to troubleshoot the problem.
132132
133133
## Configure app to support email
134134

@@ -169,6 +169,13 @@ Also in the `RegisterConfirmation` component, remove the Razor markup and code f
169169
}
170170
```
171171

172+
## Enable account confirmation after a site has users
173+
174+
Enabling account confirmation on a site with users locks out all the existing users. Existing users are locked out because their accounts aren't confirmed. To work around existing user lockout, use one of the following approaches:
175+
176+
* Update the database to mark all existing users as confirmed.
177+
* Confirm existing users. For example, batch-send emails with confirmation links.
178+
172179
## Email and activity timeout
173180

174181
The default inactivity timeout is 14 days. The following code sets the inactivity timeout to five days with sliding expiration:
@@ -199,7 +206,7 @@ The default token lifespan of the [Identity user tokens](https://github.com/dotn
199206

200207
[!INCLUDE[](~/includes/aspnetcore-repo-ref-source-links.md)]
201208

202-
To change the email token lifespan, add a custom <xref:Microsoft.AspNetCore.Identity.DataProtectorTokenProvider%601> and <xref:Microsoft.AspNetCore.Identity.DataProtectionTokenProviderOptions>:
209+
To change the email token lifespan, add a custom <xref:Microsoft.AspNetCore.Identity.DataProtectorTokenProvider%601> and <xref:Microsoft.AspNetCore.Identity.DataProtectionTokenProviderOptions>.
203210

204211
`CustomTokenProvider.cs`:
205212

@@ -275,13 +282,6 @@ builder.Services
275282
.AddTransient<CustomEmailConfirmationTokenProvider<ApplicationUser>>();
276283
```
277284

278-
## Enable account confirmation after a site has users
279-
280-
Enabling account confirmation on a site with users locks out all the existing users. Existing users are locked out because their accounts aren't confirmed. To work around existing user lockout, use one of the following approaches:
281-
282-
* Update the database to mark all existing users as confirmed.
283-
* Confirm existing users. For example, batch-send emails with confirmation links.
284-
285285
## Troubleshoot
286286

287287
If you can't get email working:

aspnetcore/blazor/security/webassembly/standalone-with-identity/account-confirmation-and-password-recovery.md

Lines changed: 41 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ author: guardrex
44
description: Learn how to configure an ASP.NET Core Blazor WebAssembly app with ASP.NET Core Identity with email confirmation and password recovery.
55
ms.author: riande
66
monikerRange: '>= aspnetcore-8.0'
7-
ms.date: 10/30/2024
7+
ms.date: 10/31/2024
88
uid: blazor/security/webassembly/standalone-with-identity/account-confirmation-and-password-recovery
99
---
1010
# Account confirmation and password recovery in ASP.NET Core Blazor WebAssembly with ASP.NET Core Identity
@@ -18,8 +18,8 @@ This article explains how to configure an ASP.NET Core Blazor WebAssembly app wi
1818

1919
The namespaces used by the examples in this article are:
2020

21-
* `Backend` for the backend server web API project.
22-
* `BlazorWasmAuth` for the front-end standalone Blazor WebAssembly app.
21+
* `Backend` for the backend server web API project ("server project" in this article).
22+
* `BlazorWasmAuth` for the front-end client standalone Blazor WebAssembly app ("client project" in this article).
2323

2424
These namespaces correspond to the projects in the `BlazorWebAssemblyStandaloneWithIdentity` sample solution in the [`dotnet/blazor-samples` GitHub repository](https://github.com/dotnet/blazor-samples). For more information, see <xref:blazor/security/webassembly/standalone-with-identity/index#sample-apps>.
2525

@@ -29,7 +29,7 @@ If you aren't using the `BlazorWebAssemblyStandaloneWithIdentity` sample solutio
2929

3030
In this article, [Mailchimp's Transactional API](https://mailchimp.com/developer/transactional/api/) is used via [Mandrill.net](https://www.nuget.org/packages/Mandrill.net) to send email. We recommend using an email service to send email rather than SMTP. SMTP is difficult to configure and secure properly. Whichever email service you use, access their guidance for .NET apps, create an account, configure an API key for their service, and install any NuGet packages required.
3131

32-
In the backend server project, create a class to fetch the secure email API key. The example in this article uses a class named `AuthMessageSenderOptions` with a `EmailAuthKey` property to hold the key.
32+
In the server project, create a class to hold the secret email provider API key. The example in this article uses a class named `AuthMessageSenderOptions` with an `EmailAuthKey` property to hold the key.
3333

3434
`AuthMessageSenderOptions.cs`:
3535

@@ -42,21 +42,21 @@ public class AuthMessageSenderOptions
4242
}
4343
```
4444

45-
Register the `AuthMessageSenderOptions` configuration instance in the backend server project's `Program` file:
45+
Register the `AuthMessageSenderOptions` configuration instance in the server project's `Program` file:
4646

4747
```csharp
4848
builder.Services.Configure<AuthMessageSenderOptions>(builder.Configuration);
4949
```
5050

5151
## Configure a user secret for the provider's security key
5252

53-
If the backend server web API project (`Backend` in the [sample solution](xref:blazor/security/webassembly/standalone-with-identity/index#sample-apps)) has already been initialized for the [Secret Manager tool](xref:security/app-secrets), it will already have a app secrets identifier (`<AppSecretsId>`) in its project file (`.csproj`). In Visual Studio, you can tell if the app secrets ID is present by looking at the **Properties** panel when the project is selected in **Solution Explorer**. If the app hasn't been initialized, execute the following command in a command shell opened to the backend server project's directory. In Visual Studio, you can use the Developer PowerShell command prompt (use the `cd` command to change the directory to the server project after you open the command shell).
53+
If the server project has already been initialized for the [Secret Manager tool](xref:security/app-secrets), it will already have a app secrets identifier (`<AppSecretsId>`) in its project file (`.csproj`). In Visual Studio, you can tell if the app secrets ID is present by looking at the **Properties** panel when the project is selected in **Solution Explorer**. If the app hasn't been initialized, execute the following command in a command shell opened to the server project's directory. In Visual Studio, you can use the Developer PowerShell command prompt (use the `cd` command to change the directory to the server project after you open the command shell).
5454

5555
```dotnetcli
5656
dotnet user-secrets init
5757
```
5858

59-
Set the email API key with the Secret Manager tool. In the following example, the key name is `EmailAuthKey`, and the key is represented by the `{KEY}` placeholder. Execute the following command with the API key:
59+
Set the API key with the Secret Manager tool. In the following example, the key name is `EmailAuthKey` to match `AuthMessageSenderOptions.EmailAuthKey`, and the key is represented by the `{KEY}` placeholder. Execute the following command with the API key:
6060

6161
```dotnetcli
6262
dotnet user-secrets set "EmailAuthKey" "{KEY}"
@@ -72,9 +72,9 @@ For more information, see <xref:security/app-secrets>.
7272

7373
The following example is based on Mailchimp's Transactional API using [Mandrill.net](https://www.nuget.org/packages/Mandrill.net). For a different provider, refer to their documentation on how to implement sending an email message.
7474

75-
Add the [Mandrill.net](https://www.nuget.org/packages/Mandrill.net) NuGet package to the backend server project.
75+
Add the [Mandrill.net](https://www.nuget.org/packages/Mandrill.net) NuGet package to the server project.
7676

77-
Add the following `EmailSender` class to implement <xref:Microsoft.AspNetCore.Identity.IEmailSender%601>. In the following example, `AppUser` is a <xref:Microsoft.AspNetCore.Identity.IdentityUser>. The message HTML markup can be further customized. As long as the `message` passed to `MandrillMessage` starts with the `<` character, the Mandrill.net API assumes that the message body is composed in HTML.
77+
Add the following `EmailSender` class to implement <xref:Microsoft.AspNetCore.Identity.IEmailSender%601>. In the following example, `AppUser` is an <xref:Microsoft.AspNetCore.Identity.IdentityUser>. The message HTML markup can be further customized. As long as the `message` passed to `MandrillMessage` starts with the `<` character, the Mandrill.net API assumes that the message body is composed in HTML.
7878

7979
`EmailSender.cs`:
8080

@@ -132,23 +132,25 @@ public class EmailSender(IOptions<AuthMessageSenderOptions> optionsAccessor,
132132
```
133133

134134
> [!NOTE]
135-
> Body content for messages might require special encoding for the email service provider. If links in the message body can't be followed, consult the service provider's documentation.
135+
> Body content for messages might require special encoding for the email service provider. If links in the message body can't be followed in the email message, consult the service provider's documentation to troubleshoot the problem.
136136
137-
## Configure the server project to support email
137+
Add the following <xref:Microsoft.AspNetCore.Identity.IEmailSender%601> service registration to the server project's `Program` file:
138138

139-
In the backend server's `Program` file, require a confirmed email to register an account. Locate the line that calls <xref:Microsoft.Extensions.DependencyInjection.IdentityServiceCollectionExtensions.AddIdentityCore%2A> and set the <xref:Microsoft.AspNetCore.Identity.SignInOptions.RequireConfirmedEmail> property to `true`:
139+
```csharp
140+
builder.Services.AddTransient<IEmailSender<AppUser>, EmailSender>();
141+
```
142+
143+
## Configure the server project to require email confirmation
144+
145+
In the server's `Program` file, require a confirmed email address to sign in to the app.
146+
147+
Locate the line that calls <xref:Microsoft.Extensions.DependencyInjection.IdentityServiceCollectionExtensions.AddIdentityCore%2A> and set the <xref:Microsoft.AspNetCore.Identity.SignInOptions.RequireConfirmedEmail> property to `true`:
140148

141149
```diff
142150
- builder.Services.AddIdentityCore<AppUser>()
143151
+ builder.Services.AddIdentityCore<AppUser>(o => o.SignIn.RequireConfirmedEmail = true)
144152
```
145153

146-
Add the following service registration to set the email sender implementation to `EmailSender` for <xref:Microsoft.AspNetCore.Identity.IEmailSender%601>:
147-
148-
```csharp
149-
builder.Services.AddTransient<IEmailSender<AppUser>, EmailSender>();
150-
```
151-
152154
## Update the client project's account registration response
153155

154156
In the client project's `Register` component (`Components/Identity/Register.razor`), change the message to users on a successful account registration to instruct them to confirm their account. The following example includes a link to trigger Identity on the server to resend the confirmation email.
@@ -191,18 +193,29 @@ In the server project's seed data class (`SeedData.cs`), change the code in the
191193
+ }
192194
```
193195

196+
## Enable account confirmation after a site has users
197+
198+
Enabling account confirmation on a site with users locks out all the existing users. Existing users are locked out because their accounts aren't confirmed. To work around existing user lockout, use one of the following approaches:
199+
200+
* Update the database to mark all existing users as confirmed.
201+
* Confirm existing users. For example, batch-send emails with confirmation links.
202+
194203
## Password recovery
195204

196-
Password recovery requires the server app to adopt an email provider in order to send password resent codes to users. Therefore, the guidance earlier in this article to enable account confirmation should be followed to enable an email provider.
205+
Password recovery requires the server app to adopt an email provider in order to send password reset codes to users. Therefore, follow the guidance earlier in this article to adopt an email provider:
206+
207+
* [Select and configure an email provider for the server project](#select-and-configure-an-email-provider-for-the-server-project)
208+
* [Configure a user secret for the provider's security key](#configure-a-user-secret-for-the-providers-security-key)
209+
* [Implement `IEmailSender` in the server project](#implement-iemailsender-in-the-server-project)
197210

198211
Password recovery is a two-step process:
199212

200213
1. A POST request is made to the `/forgotPassword` endpoint provided by <xref:Microsoft.AspNetCore.Routing.IdentityApiEndpointRouteBuilderExtensions.MapIdentityApi%2A> in the server project. A message in the UI instructs the user to check their email for a reset code.
201-
1. A POST request is made to the `/resetPassword` endpoint of the server project with the user's email addres, password reset code, and new password.
214+
1. A POST request is made to the `/resetPassword` endpoint of the server project with the user's email address, password reset code, and new password.
202215

203-
The preceding steps are demonstrated by the following implementation guidance for the [sample apps](xref:blazor/security/webassembly/standalone-with-identity/index#sample-apps).
216+
The preceding steps are demonstrated by the following implementation guidance for the [sample solution](xref:blazor/security/webassembly/standalone-with-identity/index#sample-apps).
204217

205-
Add the following method signatures to the `IAccountManagement` class (`Identity/IAccountManagement.cs`) in the client project (`BlazorWasmAuth`).
218+
In the client project, add the following method signatures to the `IAccountManagement` class (`Identity/IAccountManagement.cs`):
206219

207220
```csharp
208221
public Task<bool> ForgotPasswordAsync(string email);
@@ -211,7 +224,7 @@ public Task<FormResult> ResetPasswordAsync(string email, string resetCode,
211224
string newPassword);
212225
```
213226

214-
Provide implementations for the preceding methods in the `CookieAuthenticationStateProvider` class (`Identity/CookieAuthenticationStateProvider.cs`):
227+
In the client project, add implementations for the preceding methods in the `CookieAuthenticationStateProvider` class (`Identity/CookieAuthenticationStateProvider.cs`):
215228

216229
```csharp
217230
/// <summary>
@@ -313,7 +326,10 @@ public async Task<FormResult> ResetPasswordAsync(string email, string resetCode,
313326
}
314327
```
315328

316-
Add the following `ForgotPassword` component to the client project (`BlazorWasmAuth`). Code lines in the following component are shortened for display in this article.
329+
In the client project, add the following `ForgotPassword` component.
330+
331+
> [!NOTE]
332+
> Code lines in the following example are broken across two or more lines to eliminate or reduce horizontal scrolling in this article, but you can place the following code as shown into a test app. The code executes regardless of the artificial line breaks.
317333
318334
`Components/Identity/ForgotPassword.razor`:
319335

@@ -523,7 +539,7 @@ The default token lifespan of the [Identity user tokens](https://github.com/dotn
523539

524540
[!INCLUDE[](~/includes/aspnetcore-repo-ref-source-links.md)]
525541

526-
To change the email token lifespan, add a custom <xref:Microsoft.AspNetCore.Identity.DataProtectorTokenProvider%601> and <xref:Microsoft.AspNetCore.Identity.DataProtectionTokenProviderOptions>:
542+
To change the email token lifespan, add a custom <xref:Microsoft.AspNetCore.Identity.DataProtectorTokenProvider%601> and <xref:Microsoft.AspNetCore.Identity.DataProtectionTokenProviderOptions>.
527543

528544
`CustomTokenProvider.cs`:
529545

@@ -599,13 +615,6 @@ builder.Services
599615
.AddTransient<CustomEmailConfirmationTokenProvider<AppUser>>();
600616
```
601617

602-
## Enable account confirmation after a site has users
603-
604-
Enabling account confirmation on a site with users locks out all the existing users. Existing users are locked out because their accounts aren't confirmed. To work around existing user lockout, use one of the following approaches:
605-
606-
* Update the database to mark all existing users as confirmed.
607-
* Confirm existing users. For example, batch-send emails with confirmation links.
608-
609618
## Troubleshoot
610619

611620
If you can't get email working:

0 commit comments

Comments
 (0)