Skip to content

Commit 73b65f6

Browse files
authored
Merge pull request #17969 from dotnet/master
2 parents c9d1208 + dad2a60 commit 73b65f6

11 files changed

Lines changed: 159 additions & 143 deletions

aspnetcore/includes/blazor-security/app-component.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,17 @@ The `App` component (*App.razor*) is similar to the `App` component found in Bla
1111
<AuthorizeRouteView RouteData="@routeData"
1212
DefaultLayout="@typeof(MainLayout)">
1313
<NotAuthorized>
14-
<RedirectToLogin />
14+
@if (!context.User.Identity.IsAuthenticated)
15+
{
16+
<RedirectToLogin />
17+
}
18+
else
19+
{
20+
<p>
21+
You are not authorized to access
22+
this resource.
23+
</p>
24+
}
1525
</NotAuthorized>
1626
</AuthorizeRouteView>
1727
</Found>

aspnetcore/includes/blazor-security/redirecttologin-component.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ The `RedirectToLogin` component (*Shared/RedirectToLogin.razor*):
99
@code {
1010
protected override void OnInitialized()
1111
{
12-
Navigation.NavigateTo($"authentication/login?returnUrl={Navigation.Uri}");
12+
Navigation.NavigateTo(
13+
$"authentication/login?returnUrl={Uri.EscapeDataString(Navigation.Uri)}");
1314
}
1415
}
1516
```

aspnetcore/security/blazor/webassembly/additional-scenarios.md

Lines changed: 128 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ description:
55
monikerRange: '>= aspnetcore-3.1'
66
ms.author: riande
77
ms.custom: mvc
8-
ms.date: 04/19/2020
8+
ms.date: 04/22/2020
99
no-loc: [Blazor, SignalR]
1010
uid: security/blazor/webassembly/additional-scenarios
1111
---
@@ -289,3 +289,130 @@ The `RemoteAuthenticatorView` has one fragment that can be used per authenticati
289289
| `authentication/logged-out` | `<LogOutSucceeded>` |
290290
| `authentication/profile` | `<UserProfile>` |
291291
| `authentication/register` | `<Registering>` |
292+
293+
## Support prerendering with authentication
294+
295+
After following the guidance in one of the hosted Blazor WebAssembly app topics, use the following instructions to create an app that:
296+
297+
* Prerenders paths for which authorization isn't required.
298+
* Doesn't prerender paths for which authorization is required.
299+
300+
In the Client app's `Program` class (*Program.cs*), factor common service registrations into a separate method (for example, `ConfigureCommonServices`):
301+
302+
```csharp
303+
public class Program
304+
{
305+
public static async Task Main(string[] args)
306+
{
307+
var builder = WebAssemblyHostBuilder.CreateDefault(args);
308+
builder.RootComponents.Add<App>("app");
309+
310+
builder.Services.AddSingleton(new HttpClient
311+
{
312+
BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)
313+
});
314+
315+
services.Add...;
316+
317+
ConfigureCommonServices(builder.Services);
318+
319+
await builder.Build().RunAsync();
320+
}
321+
322+
public static void ConfigureCommonServices(IServiceCollection services)
323+
{
324+
// Common service registrations
325+
}
326+
}
327+
```
328+
329+
In the Server app's `Startup.ConfigureServices`, register the following additional services:
330+
331+
```csharp
332+
using Microsoft.AspNetCore.Components.Authorization;
333+
using Microsoft.AspNetCore.Components.Server;
334+
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
335+
336+
public void ConfigureServices(IServiceCollection services)
337+
{
338+
...
339+
340+
services.AddRazorPages();
341+
services.AddScoped<AuthenticationStateProvider, ServerAuthenticationStateProvider>();
342+
services.AddScoped<SignOutSessionStateManager>();
343+
344+
Client.Program.ConfigureCommonServices(services);
345+
}
346+
```
347+
348+
In the Server app's `Startup.Configure` method, replace `endpoints.MapFallbackToFile("index.html")` with `endpoints.MapFallbackToPage("/_Host")`:
349+
350+
```csharp
351+
app.UseEndpoints(endpoints =>
352+
{
353+
endpoints.MapControllers();
354+
endpoints.MapFallbackToPage("/_Host");
355+
});
356+
```
357+
358+
In the Server app, create a *Pages* folder if it doesn't exist. Create a *_Host.cshtml* page inside the Server app's *Pages* folder. Paste the contents from the Client app's *wwwroot/index.html* file into the *Pages/_Host.cshtml* file. Update the file's contents:
359+
360+
* Add `@page "_Host"` to the top of the file.
361+
* Replace the `<app>Loading...</app>` tag with the following:
362+
363+
```cshtml
364+
<app>
365+
@if (!HttpContext.Request.Path.StartsWithSegments("/authentication"))
366+
{
367+
<component type="typeof(Wasm.Authentication.Client.App)" render-mode="Static" />
368+
}
369+
else
370+
{
371+
<text>Loading...</text>
372+
}
373+
</app>
374+
```
375+
376+
## Options for hosted apps and third-party login providers
377+
378+
When authenticating and authorizing a hosted Blazor WebAssembly app with a third-party provider, there are several options available for authenticating the user. Which one you choose depends on your scenario.
379+
380+
For more information, see <xref:security/authentication/social/additional-claims>.
381+
382+
### Authenticate users to only call protected third party APIs
383+
384+
Authenticate the user with a client-side OAuth flow against the third-party API provider:
385+
386+
```csharp
387+
builder.services.AddOidcAuthentication(options => { ... });
388+
```
389+
390+
In this scenario:
391+
392+
* The server hosting the app doesn't play a role.
393+
* APIs on the server can't be protected.
394+
* The app can only call protected third-party APIs.
395+
396+
### Authenticate users with a third-party provider and call protected APIs on the host server and the third party
397+
398+
Configure Identity with a third-party login provider. Obtain the tokens required for third-party API access and store them.
399+
400+
When a user logs in, Identity collects access and refresh tokens as part of the authentication process. At that point, there are a couple of approaches available for making API calls to third-party APIs.
401+
402+
#### Use a server access token to retrieve the third-party access token
403+
404+
Use the access token generated on the server to retrieve the third-party access token from a server API endpoint. From there, use the third-party access token to call third-party API resources directly from Identity on the client.
405+
406+
We don't recommend this approach. This approach requires treating the third-party access token as if it were generated for a public client. In OAuth terms, the public app doesn't have a client secret because it can't be trusted to store secrets safely, and the access token is produced for a confidential client. A confidential client is a client that has a client secret and is assumed to be able to safely store secrets.
407+
408+
* The third-party access token might be granted additional scopes to perform sensitive operations based on the fact that the third-party emitted the token for a more trusted client.
409+
* Similarly, refresh tokens shouldn't be issued to a client that isn't trusted, as doing so gives the client unlimited access unless other restrictions are put into place.
410+
411+
#### Make API calls from the client to the server API in order to call third-party APIs
412+
413+
Make an API call from the client to the server API. From the server, retrieve the access token for the third-party API resource and issue whatever call is necessary.
414+
415+
While this approach requires an extra network hop through the server to call a third-party API, it ultimately results in a safer experience:
416+
417+
* The server can store refresh tokens and ensure that the app doesn't lose access to third-party resources.
418+
* The app can't leak access tokens from the server that might contain more sensitive permissions.

aspnetcore/security/blazor/webassembly/hosted-with-azure-active-directory-b2c.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ description:
55
monikerRange: '>= aspnetcore-3.1'
66
ms.author: riande
77
ms.custom: mvc
8-
ms.date: 04/09/2020
8+
ms.date: 04/22/2020
99
no-loc: [Blazor, SignalR]
1010
uid: security/blazor/webassembly/hosted-with-azure-active-directory-b2c
1111
---
@@ -304,7 +304,7 @@ Run the app from the Server project. When using Visual Studio, select the Server
304304
305305
## Additional resources
306306
307-
* [Request additional access tokens](xref:security/blazor/webassembly/additional-scenarios#request-additional-access-tokens)
307+
* <xref:security/blazor/webassembly/additional-scenarios>
308308
* <xref:security/authentication/azure-ad-b2c>
309309
* [Tutorial: Create an Azure Active Directory B2C tenant](/azure/active-directory-b2c/tutorial-create-tenant)
310310
* [Microsoft identity platform documentation](/azure/active-directory/develop/)

aspnetcore/security/blazor/webassembly/hosted-with-azure-active-directory.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ description:
55
monikerRange: '>= aspnetcore-3.1'
66
ms.author: riande
77
ms.custom: mvc
8-
ms.date: 04/08/2020
8+
ms.date: 04/22/2020
99
no-loc: [Blazor, SignalR]
1010
uid: security/blazor/webassembly/hosted-with-azure-active-directory
1111
---
@@ -290,6 +290,6 @@ Run the app from the Server project. When using Visual Studio, select the Server
290290
291291
## Additional resources
292292
293-
* [Request additional access tokens](xref:security/blazor/webassembly/additional-scenarios#request-additional-access-tokens)
293+
* <xref:security/blazor/webassembly/additional-scenarios>
294294
* <xref:security/authentication/azure-active-directory/index>
295295
* [Microsoft identity platform documentation](/azure/active-directory/develop/)

aspnetcore/security/blazor/webassembly/hosted-with-identity-server.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ description: To create a new Blazor hosted app with authentication from within V
55
monikerRange: '>= aspnetcore-3.1'
66
ms.author: riande
77
ms.custom: mvc
8-
ms.date: 03/30/2020
8+
ms.date: 04/22/2020
99
no-loc: [Blazor, SignalR]
1010
uid: security/blazor/webassembly/hosted-with-identity-server
1111
---
@@ -230,4 +230,4 @@ Run the app from the Server project. When using Visual Studio, select the Server
230230

231231
## Additional resources
232232

233-
* [Request additional access tokens](xref:security/blazor/webassembly/additional-scenarios#request-additional-access-tokens)
233+
* <xref:security/blazor/webassembly/additional-scenarios>

aspnetcore/security/blazor/webassembly/index.md

Lines changed: 4 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ description: Learn how to secure Blazor WebAssemlby apps as Single Page Applicat
55
monikerRange: '>= aspnetcore-3.1'
66
ms.author: riande
77
ms.custom: mvc
8-
ms.date: 04/19/2020
8+
ms.date: 04/22/2020
99
no-loc: [Blazor, SignalR]
1010
uid: security/blazor/webassembly/index
1111
---
@@ -47,129 +47,7 @@ The `Microsoft.AspNetCore.Components.WebAssembly.Authentication` library offers
4747
* If the authentication process completes successfully, the user is authenticated and optionally sent back to the original protected URL that the user requested.
4848
* If the authentication process fails for any reason, the user is sent to the login failed page (`/authentication/login-failed`), and an error is displayed.
4949

50-
## Support prerendering with authentication
50+
## Additional resources
5151

52-
After following the guidance in one of the hosted Blazor WebAssembly app topics, use the following instructions to create an app that:
53-
54-
* Prerenders paths for which authorization isn't required.
55-
* Doesn't prerender paths for which authorization is required.
56-
57-
In the Client app's `Program` class (*Program.cs*), factor common service registrations into a separate method (for example, `ConfigureCommonServices`):
58-
59-
```csharp
60-
public class Program
61-
{
62-
public static async Task Main(string[] args)
63-
{
64-
var builder = WebAssemblyHostBuilder.CreateDefault(args);
65-
builder.RootComponents.Add<App>("app");
66-
67-
builder.Services.AddSingleton(new HttpClient
68-
{
69-
BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)
70-
});
71-
72-
services.Add...;
73-
74-
ConfigureCommonServices(builder.Services);
75-
76-
await builder.Build().RunAsync();
77-
}
78-
79-
public static void ConfigureCommonServices(IServiceCollection services)
80-
{
81-
// Common service registrations
82-
}
83-
}
84-
```
85-
86-
In the Server app's `Startup.ConfigureServices`, register the following additional services:
87-
88-
```csharp
89-
using Microsoft.AspNetCore.Components.Authorization;
90-
using Microsoft.AspNetCore.Components.Server;
91-
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
92-
93-
public void ConfigureServices(IServiceCollection services)
94-
{
95-
...
96-
97-
services.AddRazorPages();
98-
services.AddScoped<AuthenticationStateProvider, ServerAuthenticationStateProvider>();
99-
services.AddScoped<SignOutSessionStateManager>();
100-
101-
Client.Program.ConfigureCommonServices(services);
102-
}
103-
```
104-
105-
In the Server app's `Startup.Configure` method, replace `endpoints.MapFallbackToFile("index.html")` with `endpoints.MapFallbackToPage("/_Host")`:
106-
107-
```csharp
108-
app.UseEndpoints(endpoints =>
109-
{
110-
endpoints.MapControllers();
111-
endpoints.MapFallbackToPage("/_Host");
112-
});
113-
```
114-
115-
In the Server app, create a *Pages* folder if it doesn't exist. Create a *_Host.cshtml* page inside the Server app's *Pages* folder. Paste the contents from the Client app's *wwwroot/index.html* file into the *Pages/_Host.cshtml* file. Update the file's contents:
116-
117-
* Add `@page "_Host"` to the top of the file.
118-
* Replace the `<app>Loading...</app>` tag with the following:
119-
120-
```cshtml
121-
<app>
122-
@if (!HttpContext.Request.Path.StartsWithSegments("/authentication"))
123-
{
124-
<component type="typeof(Wasm.Authentication.Client.App)" render-mode="Static" />
125-
}
126-
else
127-
{
128-
<text>Loading...</text>
129-
}
130-
</app>
131-
```
132-
133-
## Options for hosted apps and third-party login providers
134-
135-
When authenticating and authorizing a hosted Blazor WebAssembly app with a third-party provider, there are several options available for authenticating the user. Which one you choose depends on your scenario.
136-
137-
For more information, see <xref:security/authentication/social/additional-claims>.
138-
139-
### Authenticate users to only call protected third party APIs
140-
141-
Authenticate the user with a client-side OAuth flow against the third-party API provider:
142-
143-
```csharp
144-
builder.services.AddOidcAuthentication(options => { ... });
145-
```
146-
147-
In this scenario:
148-
149-
* The server hosting the app doesn't play a role.
150-
* APIs on the server can't be protected.
151-
* The app can only call protected third-party APIs.
152-
153-
### Authenticate users with a third-party provider and call protected APIs on the host server and the third party
154-
155-
Configure Identity with a third-party login provider. Obtain the tokens required for third-party API access and store them.
156-
157-
When a user logs in, Identity collects access and refresh tokens as part of the authentication process. At that point, there are a couple of approaches available for making API calls to third-party APIs.
158-
159-
#### Use a server access token to retrieve the third-party access token
160-
161-
Use the access token generated on the server to retrieve the third-party access token from a server API endpoint. From there, use the third-party access token to call third-party API resources directly from Identity on the client.
162-
163-
We don't recommend this approach. This approach requires treating the third-party access token as if it were generated for a public client. In OAuth terms, the public app doesn't have a client secret because it can't be trusted to store secrets safely, and the access token is produced for a confidential client. A confidential client is a client that has a client secret and is assumed to be able to safely store secrets.
164-
165-
* The third-party access token might be granted additional scopes to perform sensitive operations based on the fact that the third-party emitted the token for a more trusted client.
166-
* Similarly, refresh tokens shouldn't be issued to a client that isn't trusted, as doing so gives the client unlimited access unless other restrictions are put into place.
167-
168-
#### Make API calls from the client to the server API in order to call third-party APIs
169-
170-
Make an API call from the client to the server API. From the server, retrieve the access token for the third-party API resource and issue whatever call is necessary.
171-
172-
While this approach requires an extra network hop through the server to call a third-party API, it ultimately results in a safer experience:
173-
174-
* The server can store refresh tokens and ensure that the app doesn't lose access to third-party resources.
175-
* The app can't leak access tokens from the server that might contain more sensitive permissions.
52+
* Articles under this *Overview* provide information on authenticating users in Blazor WebAssembly apps against specific providers.
53+
* <xref:security/blazor/webassembly/additional-scenarios>

aspnetcore/security/blazor/webassembly/standalone-with-authentication-library.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ description:
55
monikerRange: '>= aspnetcore-3.1'
66
ms.author: riande
77
ms.custom: mvc
8-
ms.date: 04/08/2020
8+
ms.date: 04/22/2020
99
no-loc: [Blazor, SignalR]
1010
uid: security/blazor/webassembly/standalone-with-authentication-library
1111
---
@@ -114,4 +114,4 @@ For more information, see <xref:security/blazor/webassembly/additional-scenarios
114114
115115
## Additional resources
116116
117-
* [Request additional access tokens](xref:security/blazor/webassembly/additional-scenarios#request-additional-access-tokens)
117+
* <xref:security/blazor/webassembly/additional-scenarios>

aspnetcore/security/blazor/webassembly/standalone-with-azure-active-directory-b2c.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ description:
55
monikerRange: '>= aspnetcore-3.1'
66
ms.author: riande
77
ms.custom: mvc
8-
ms.date: 04/09/2020
8+
ms.date: 04/22/2020
99
no-loc: [Blazor, SignalR]
1010
uid: security/blazor/webassembly/standalone-with-azure-active-directory-b2c
1111
---
@@ -139,7 +139,7 @@ For more information, see <xref:security/blazor/webassembly/additional-scenarios
139139
140140
## Additional resources
141141
142-
* [Request additional access tokens](xref:security/blazor/webassembly/additional-scenarios#request-additional-access-tokens)
142+
* <xref:security/blazor/webassembly/additional-scenarios>
143143
* <xref:security/authentication/azure-ad-b2c>
144144
* [Tutorial: Create an Azure Active Directory B2C tenant](/azure/active-directory-b2c/tutorial-create-tenant)
145145
* [Microsoft identity platform documentation](/azure/active-directory/develop/)

0 commit comments

Comments
 (0)