Skip to content

Commit 9c88b58

Browse files
committed
Address feedback:
* Remove signout Component * Move IRemoteAuthenticationPathsProvider to the .Internal namespace. * Change the API for GetAccessToken
1 parent 2e4dabc commit 9c88b58

14 files changed

+92
-68
lines changed

src/Components/Blazor/WebAssembly.Authentication/src/DefaultRemoteApplicationPathsProvider.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

4-
using Microsoft.AspNetCore.Components.WebAssembly.Authentication.Infrastructure;
4+
using Microsoft.AspNetCore.Components.WebAssembly.Authentication.Internal;
55
using Microsoft.Extensions.Options;
66

77
namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication

src/Components/Blazor/WebAssembly.Authentication/src/IRemoteAuthenticationPathsProvider.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

4-
namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication.Infrastructure
4+
namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication.Internal
55
{
66
/// <summary>
77
/// This is an internal API that supports the Microsoft.AspNetCore.Components.WebAssembly.Authentication

src/Components/Blazor/WebAssembly.Authentication/src/RemoteAuthenticatorViewCore.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
using System.Threading.Tasks;
66
using Microsoft.AspNetCore.Components.Authorization;
77
using Microsoft.AspNetCore.Components.Rendering;
8-
using Microsoft.AspNetCore.Components.WebAssembly.Authentication.Infrastructure;
8+
using Microsoft.AspNetCore.Components.WebAssembly.Authentication.Internal;
99
using Microsoft.JSInterop;
1010

1111
namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
@@ -92,7 +92,9 @@ public class RemoteAuthenticatorViewCore<TAuthenticationState> : ComponentBase w
9292
/// <summary>
9393
/// Gets or sets a default <see cref="IRemoteAuthenticationPathsProvider"/> to use as fallback if an <see cref="ApplicationPaths"/> has not been explicitly specified.
9494
/// </summary>
95+
#pragma warning disable PUB0001 // Pubternal type in public API
9596
[Inject] public IRemoteAuthenticationPathsProvider RemoteApplicationPathsProvider { get; set; }
97+
#pragma warning restore PUB0001 // Pubternal type in public API
9698

9799
/// <summary>
98100
/// Gets or sets a default <see cref="AuthenticationStateProvider"/> with the current user.

src/Components/Blazor/WebAssembly.Authentication/src/Services/AccessTokenResult.cs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,20 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
1010
/// </summary>
1111
public class AccessTokenResult
1212
{
13+
private AccessToken _token;
14+
15+
public AccessTokenResult(string status, AccessToken token, string redirectUrl)
16+
{
17+
Status = status;
18+
_token = token;
19+
RedirectUrl = redirectUrl;
20+
}
21+
1322
/// <summary>
1423
/// Gets or sets the status of the current operation. See <see cref="AccessTokenResultStatus"/> for a list of statuses.
1524
/// </summary>
1625
public string Status { get; set; }
1726

18-
/// <summary>
19-
/// Gets or sets the <see cref="AccessToken"/> if <see cref="Status"/> is <see cref="AccessTokenResultStatus.Success"/>.
20-
/// </summary>
21-
public AccessToken Token { get; set; }
22-
2327
/// <summary>
2428
/// Gets or sets the URL to redirect to if <see cref="Status"/> is <see cref="AccessTokenResultStatus.RequiresRedirect"/>.
2529
/// </summary>
@@ -30,11 +34,11 @@ public class AccessTokenResult
3034
/// </summary>
3135
/// <param name="accessToken">The <see cref="AccessToken"/> if the request was successful.</param>
3236
/// <returns><c>true</c> when the token request is successful; <c>false</c> otherwise.</returns>
33-
public bool TryGetAccessToken(out AccessToken accessToken)
37+
public bool TryGetToken(out AccessToken accessToken)
3438
{
3539
if (string.Equals(Status, AccessTokenResultStatus.Success, StringComparison.OrdinalIgnoreCase))
3640
{
37-
accessToken = Token;
41+
accessToken = _token;
3842
return true;
3943
}
4044
else

src/Components/Blazor/WebAssembly.Authentication/src/Services/IAccessTokenProvider.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@ public interface IAccessTokenProvider
1414
/// Tries to get an access token for the current user with the default set of permissions.
1515
/// </summary>
1616
/// <returns>A <see cref="ValueTask{AccessTokenResult}"/> that will return contain the <see cref="AccessTokenResult"/> when completed.</returns>
17-
ValueTask<AccessTokenResult> GetAccessToken();
17+
ValueTask<AccessTokenResult> RequestAccessToken();
1818

1919
/// <summary>
2020
/// Tries to get an access token with the options specified in <see cref="AccessTokenRequestOptions"/>.
2121
/// </summary>
2222
/// <param name="options">The <see cref="AccessTokenRequestOptions"/> for provisioning the access token.</param>
2323
/// <returns>A <see cref="ValueTask{AccessTokenResult}"/> that will return contain the <see cref="AccessTokenResult"/> when completed.</returns>
24-
ValueTask<AccessTokenResult> GetAccessToken(AccessTokenRequestOptions options);
24+
ValueTask<AccessTokenResult> RequestAccessToken(AccessTokenRequestOptions options);
2525
}
2626
}

src/Components/Blazor/WebAssembly.Authentication/src/Services/IRemoteAuthenticationService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
1010
/// Represents a contract for services that perform authentication operations for a Blazor WebAssembly application.
1111
/// </summary>
1212
/// <typeparam name="TRemoteAuthenticationState">The state to be persisted across authentication operations.</typeparam>
13-
public interface IRemoteAuthenticationService<TRemoteAuthenticationState> : IAccessTokenProvider
13+
public interface IRemoteAuthenticationService<TRemoteAuthenticationState>
1414
where TRemoteAuthenticationState : RemoteAuthenticationState
1515
{
1616
/// <summary>

src/Components/Blazor/WebAssembly.Authentication/src/Services/RemoteAuthenticationService.cs

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
1717
/// </summary>
1818
/// <typeparam name="TRemoteAuthenticationState">The state to preserve across authentication operations.</typeparam>
1919
/// <typeparam name="TProviderOptions">The options to be passed down to the underlying JavaScript library handling the authentication operations.</typeparam>
20-
public class RemoteAuthenticationService<TRemoteAuthenticationState, TProviderOptions> : AuthenticationStateProvider, IRemoteAuthenticationService<TRemoteAuthenticationState>
20+
public class RemoteAuthenticationService<TRemoteAuthenticationState, TProviderOptions> :
21+
AuthenticationStateProvider,
22+
IRemoteAuthenticationService<TRemoteAuthenticationState>,
23+
IAccessTokenProvider
2124
where TRemoteAuthenticationState : RemoteAuthenticationState
2225
where TProviderOptions : new()
2326
{
@@ -118,33 +121,46 @@ public virtual async Task<RemoteAuthenticationResult<TRemoteAuthenticationState>
118121
}
119122

120123
/// <inheritdoc />
121-
public virtual async ValueTask<AccessTokenResult> GetAccessToken()
124+
public virtual async ValueTask<AccessTokenResult> RequestAccessToken()
122125
{
123126
await EnsureAuthService();
124-
return await _jsRuntime.InvokeAsync<AccessTokenResult>("AuthenticationService.getAccessToken");
127+
var result = await _jsRuntime.InvokeAsync<InternalAccessTokenResult>("AuthenticationService.getAccessToken");
128+
129+
var redirectUrl = GetRedirectUrl(null);
130+
if (string.Equals(result.Status, AccessTokenResultStatus.RequiresRedirect, StringComparison.OrdinalIgnoreCase))
131+
{
132+
result.RedirectUrl = redirectUrl.ToString();
133+
}
134+
135+
return new AccessTokenResult(result.Status, result.Token, result.RedirectUrl);
125136
}
126137

127138
/// <inheritdoc />
128-
public virtual async ValueTask<AccessTokenResult> GetAccessToken(AccessTokenRequestOptions options)
139+
public virtual async ValueTask<AccessTokenResult> RequestAccessToken(AccessTokenRequestOptions options)
129140
{
130141
if (options is null)
131142
{
132143
throw new ArgumentNullException(nameof(options));
133144
}
134145

135146
await EnsureAuthService();
136-
var result = await _jsRuntime.InvokeAsync<AccessTokenResult>("AuthenticationService.getAccessToken", options);
137-
138-
var returnUrl = options.ReturnUrl != null ? _navigation.ToAbsoluteUri(options.ReturnUrl).ToString() : null;
139-
var encodedReturnUrl = Uri.EscapeDataString(returnUrl ?? _navigation.Uri);
140-
var redirectUrl = _navigation.ToAbsoluteUri($"{_options.AuthenticationPaths.LogInPath}?returnUrl={encodedReturnUrl}");
147+
var result = await _jsRuntime.InvokeAsync<InternalAccessTokenResult>("AuthenticationService.getAccessToken", options);
141148

149+
var redirectUrl = GetRedirectUrl(options?.ReturnUrl);
142150
if (string.Equals(result.Status, AccessTokenResultStatus.RequiresRedirect, StringComparison.OrdinalIgnoreCase))
143151
{
144152
result.RedirectUrl = redirectUrl.ToString();
145153
}
146154

147-
return result;
155+
return new AccessTokenResult(result.Status, result.Token, result.RedirectUrl);
156+
}
157+
158+
private Uri GetRedirectUrl(string customReturnUrl)
159+
{
160+
var returnUrl = customReturnUrl != null ? _navigation.ToAbsoluteUri(customReturnUrl).ToString() : null;
161+
var encodedReturnUrl = Uri.EscapeDataString(returnUrl ?? _navigation.Uri);
162+
var redirectUrl = _navigation.ToAbsoluteUri($"{_options.AuthenticationPaths.LogInPath}?returnUrl={encodedReturnUrl}");
163+
return redirectUrl;
148164
}
149165

150166
private async ValueTask<ClaimsPrincipal> GetUser(bool useCache = false)
@@ -217,4 +233,12 @@ private void UpdateUser(ValueTask<ClaimsPrincipal> task)
217233
static async Task<AuthenticationState> UpdateAuthenticationState(ValueTask<ClaimsPrincipal> futureUser) => new AuthenticationState(await futureUser);
218234
}
219235
}
236+
237+
// Internal for testing purposes
238+
internal struct InternalAccessTokenResult
239+
{
240+
public string Status { get; set; }
241+
public AccessToken Token { get; set; }
242+
public string RedirectUrl { get; set; }
243+
}
220244
}

src/Components/Blazor/WebAssembly.Authentication/src/SignOut.razor

Lines changed: 0 additions & 20 deletions
This file was deleted.

src/Components/Blazor/WebAssembly.Authentication/src/WebAssemblyAuthenticationServiceCollectionExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
using System.Reflection;
66
using Microsoft.AspNetCore.Components.Authorization;
77
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
8-
using Microsoft.AspNetCore.Components.WebAssembly.Authentication.Infrastructure;
8+
using Microsoft.AspNetCore.Components.WebAssembly.Authentication.Internal;
99
using Microsoft.Extensions.DependencyInjection.Extensions;
1010
using Microsoft.Extensions.Options;
1111

src/Components/Blazor/WebAssembly.Authentication/test/RemoteAuthenticationServiceTests.cs

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ public async Task RemoteAuthenticationService_GetAccessToken_ReturnsAccessTokenR
248248
new TestNavigationManager());
249249

250250
var state = new RemoteAuthenticationState();
251-
testJsRuntime.GetAccessTokenResult = new AccessTokenResult
251+
testJsRuntime.GetAccessTokenResult = new InternalAccessTokenResult
252252
{
253253
Status = AccessTokenResultStatus.Success,
254254
Token = new AccessToken
@@ -260,14 +260,17 @@ public async Task RemoteAuthenticationService_GetAccessToken_ReturnsAccessTokenR
260260
};
261261

262262
// Act
263-
var result = await runtime.GetAccessToken();
263+
var result = await runtime.RequestAccessToken();
264264

265265
// Assert
266266
Assert.Equal(
267267
new[] { "AuthenticationService.init", "AuthenticationService.getAccessToken" },
268268
testJsRuntime.PastInvocations.Select(i => i.identifier).ToArray());
269269

270-
Assert.Equal(result, testJsRuntime.GetAccessTokenResult);
270+
Assert.True(result.TryGetToken(out var token));
271+
Assert.Equal(result.Status, testJsRuntime.GetAccessTokenResult.Status);
272+
Assert.Equal(result.RedirectUrl, testJsRuntime.GetAccessTokenResult.RedirectUrl);
273+
Assert.Equal(token, testJsRuntime.GetAccessTokenResult.Token);
271274
}
272275

273276
[Fact]
@@ -282,7 +285,7 @@ public async Task RemoteAuthenticationService_GetAccessToken_PassesDownOptions()
282285
new TestNavigationManager());
283286

284287
var state = new RemoteAuthenticationState();
285-
testJsRuntime.GetAccessTokenResult = new AccessTokenResult
288+
testJsRuntime.GetAccessTokenResult = new InternalAccessTokenResult
286289
{
287290
Status = AccessTokenResultStatus.RequiresRedirect,
288291
};
@@ -295,14 +298,16 @@ public async Task RemoteAuthenticationService_GetAccessToken_PassesDownOptions()
295298
var expectedRedirectUrl = "https://www.example.com/base/login?returnUrl=https%3A%2F%2Fwww.example.com%2Fbase%2Fadd-product";
296299

297300
// Act
298-
var result = await runtime.GetAccessToken(tokenOptions);
301+
var result = await runtime.RequestAccessToken(tokenOptions);
299302

300303
// Assert
301304
Assert.Equal(
302305
new[] { "AuthenticationService.init", "AuthenticationService.getAccessToken" },
303306
testJsRuntime.PastInvocations.Select(i => i.identifier).ToArray());
304307

305-
Assert.Equal(result, testJsRuntime.GetAccessTokenResult);
308+
Assert.False(result.TryGetToken(out var token));
309+
Assert.Null(token);
310+
Assert.Equal(result.Status, testJsRuntime.GetAccessTokenResult.Status);
306311
Assert.Equal(expectedRedirectUrl, result.RedirectUrl);
307312
Assert.Equal(tokenOptions, (AccessTokenRequestOptions)testJsRuntime.PastInvocations[^1].args[0]);
308313
}
@@ -319,7 +324,7 @@ public async Task RemoteAuthenticationService_GetAccessToken_ComputesDefaultRetu
319324
new TestNavigationManager());
320325

321326
var state = new RemoteAuthenticationState();
322-
testJsRuntime.GetAccessTokenResult = new AccessTokenResult
327+
testJsRuntime.GetAccessTokenResult = new InternalAccessTokenResult
323328
{
324329
Status = AccessTokenResultStatus.RequiresRedirect,
325330
};
@@ -333,14 +338,16 @@ public async Task RemoteAuthenticationService_GetAccessToken_ComputesDefaultRetu
333338
var expectedRedirectUrl = "https://www.example.com/base/login?returnUrl=https%3A%2F%2Fwww.example.com%2Fbase%2Fadd-saved-product%2F123413241234";
334339

335340
// Act
336-
var result = await runtime.GetAccessToken(tokenOptions);
341+
var result = await runtime.RequestAccessToken(tokenOptions);
337342

338343
// Assert
339344
Assert.Equal(
340345
new[] { "AuthenticationService.init", "AuthenticationService.getAccessToken" },
341346
testJsRuntime.PastInvocations.Select(i => i.identifier).ToArray());
342347

343-
Assert.Equal(result, testJsRuntime.GetAccessTokenResult);
348+
Assert.False(result.TryGetToken(out var token));
349+
Assert.Null(token);
350+
Assert.Equal(result.Status, testJsRuntime.GetAccessTokenResult.Status);
344351
Assert.Equal(expectedRedirectUrl, result.RedirectUrl);
345352
Assert.Equal(tokenOptions, (AccessTokenRequestOptions)testJsRuntime.PastInvocations[^1].args[0]);
346353
}
@@ -423,7 +430,7 @@ public async Task RemoteAuthenticationService_GetUser_DoesNotMapScopesToRoles()
423430
}, serializationOptions);
424431

425432
testJsRuntime.GetUserResult = JsonSerializer.Deserialize<IDictionary<string, object>>(serializedUser);
426-
testJsRuntime.GetAccessTokenResult = new AccessTokenResult
433+
testJsRuntime.GetAccessTokenResult = new InternalAccessTokenResult
427434
{
428435
Status = AccessTokenResultStatus.Success,
429436
Token = new AccessToken
@@ -499,7 +506,7 @@ private class TestJsRuntime : IJSRuntime
499506

500507
public RemoteAuthenticationResult<RemoteAuthenticationState> InitResult { get; set; }
501508

502-
public AccessTokenResult GetAccessTokenResult { get; set; }
509+
public InternalAccessTokenResult GetAccessTokenResult { get; set; }
503510

504511
public IDictionary<string, object> GetUserResult { get; set; }
505512

src/Components/Blazor/testassets/Wasm.Authentication.Client/App.razor

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<CascadingAuthenticationState>
1+
<CascadingAuthenticationState>
22
<Router AppAssembly="@typeof(Program).Assembly">
33
<Found Context="routeData">
44
<AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
@@ -13,4 +13,4 @@
1313
</LayoutView>
1414
</NotFound>
1515
</Router>
16-
</CascadingAuthenticationState>
16+
</CascadingAuthenticationState>

src/Components/Blazor/testassets/Wasm.Authentication.Client/Pages/FetchData.razor

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,11 @@ else
4545
var httpClient = new HttpClient();
4646
httpClient.BaseAddress = new Uri(Navigation.BaseUri);
4747

48-
var tokenResult = await AuthenticationService.GetAccessToken();
48+
var tokenResult = await AuthenticationService.RequestAccessToken();
4949

50-
if (tokenResult.TryGetAccessToken(out var token))
50+
if (tokenResult.TryGetToken(out var token))
5151
{
52-
httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {tokenResult.Token.Value}");
52+
httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {token.Value}");
5353
forecasts = await httpClient.GetJsonAsync<WeatherForecast[]>("WeatherForecast");
5454
}
5555
else

src/Components/Blazor/testassets/Wasm.Authentication.Client/Pages/User.razor

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,13 @@
4444
{
4545
await base.OnInitializedAsync();
4646
var state = await AuthenticationState;
47-
var accessTokenResult = await AuthorizationService.GetAccessToken();
48-
if (accessTokenResult.Status != AccessTokenResultStatus.Success)
47+
var accessTokenResult = await AuthorizationService.RequestAccessToken();
48+
if (!accessTokenResult.TryGetToken(out var token))
4949
{
5050
throw new InvalidOperationException("Failed to provision the access token.");
5151
}
5252

53-
AccessToken = accessTokenResult.Token;
53+
AccessToken = token;
5454

5555
AuthenticatedUser = state.User;
5656
}
Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,22 @@
11
@using Microsoft.AspNetCore.Components.Authorization
2+
@inject NavigationManager Navigation
3+
@inject SignOutSessionStateManager SignOutManager
4+
25
<AuthorizeView Context="authenticationState">
36
<Authorized>
47
<a href="authentication/profile">Hello, @authenticationState.User.Identity.Name!</a>
5-
<SignOut>
6-
<OnSignOut Context="BeginSignOut">
7-
<button class="nav-link btn btn-link" @onclick="BeginSignOut">Log out</button>
8-
</OnSignOut>
9-
</SignOut>
8+
<button class="nav-link btn btn-link" @onclick="BeginSignOut">Log out</button>
109
</Authorized>
1110
<NotAuthorized>
1211
<a href="authentication/register">Register</a>
1312
<a href="authentication/login">Log in</a>
1413
</NotAuthorized>
1514
</AuthorizeView>
15+
16+
@code{
17+
public async Task BeginSignOut()
18+
{
19+
await SignOutManager.SetSignOutState();
20+
Navigation.NavigateTo("authentication/logout");
21+
}
22+
}

0 commit comments

Comments
 (0)