Skip to content

Commit c785b1a

Browse files
authored
feat:update state manager (#773)
* feat(TeamStateManager): add support for WASM and Server modes - Implemented ITeamStateManager interface for managing team states. - Added registration logic for team state manager in ServiceCollectionExtensions.cs. - Created ServerTeamStateManager and WasmTeamStateManager to handle team state management in respective environments. - Updated User.razor to utilize the new team state manager for fetching user team information. * feat:update WasmTeamStateManager refresh token * fix:navigate page
1 parent 705822f commit c785b1a

File tree

3 files changed

+70
-22
lines changed

3 files changed

+70
-22
lines changed

src/Masa.Stack.Components/Extensions/ServiceCollectionExtensions.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
namespace Masa.Stack.Components;
1+
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
2+
3+
namespace Masa.Stack.Components;
24

35
public static class ServiceCollectionExtensions
46
{
@@ -40,10 +42,12 @@ private static void AddMasaStackComponentsService(IServiceCollection services, M
4042
// 检测是否为 WASM 模式
4143
if (IsWebAssemblyEnvironment(sp))
4244
{
43-
// WASM 模式:使用页面刷新获取最新的 token 和 claims
45+
// WASM 模式:使用 refresh token 获取最新的 token 和 claims
4446
var authStateProvider = sp.GetRequiredService<AuthenticationStateProvider>();
4547
var navigationManager = sp.GetRequiredService<NavigationManager>();
46-
return new WasmTeamStateManager(authStateProvider, navigationManager);
48+
var tokenProvider = sp.GetRequiredService<IAccessTokenProvider>();
49+
var logger = sp.GetRequiredService<ILogger<WasmTeamStateManager>>();
50+
return new WasmTeamStateManager(authStateProvider, navigationManager, tokenProvider, logger);
4751
}
4852
else
4953
{

src/Masa.Stack.Components/Infrastructure/Identity/WasmTeamStateManager.cs

Lines changed: 62 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,89 @@
1+
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
2+
13
namespace Masa.Stack.Components.Infrastructure.Identity;
24

35
/// <summary>
46
/// WASM 模式的团队状态管理器
5-
/// 在 WASM 模式下,通过页面刷新获取包含最新团队信息的 token
6-
/// 经测试发现 RequestAccessToken() 只返回缓存的 token,不会真正刷新,所以使用页面刷新确保可靠性
7+
/// 在 WASM 模式下,通过 refresh token 获取包含最新团队信息的 token
78
/// </summary>
89
public class WasmTeamStateManager : ITeamStateManager, IScopedDependency
910
{
1011
private readonly AuthenticationStateProvider _authenticationStateProvider;
1112
private readonly NavigationManager _navigationManager;
13+
private readonly IAccessTokenProvider _accessTokenProvider;
14+
private readonly ILogger<WasmTeamStateManager> _logger;
1215

1316
public WasmTeamStateManager(
1417
AuthenticationStateProvider authenticationStateProvider,
15-
NavigationManager navigationManager)
18+
NavigationManager navigationManager,
19+
IAccessTokenProvider accessTokenProvider,
20+
ILogger<WasmTeamStateManager> logger)
1621
{
1722
_authenticationStateProvider = authenticationStateProvider;
1823
_navigationManager = navigationManager;
24+
_accessTokenProvider = accessTokenProvider;
25+
_logger = logger;
26+
}
27+
28+
/// <summary>
29+
/// 强制刷新 token,通过清除当前 token 来触发 refresh token 流程
30+
/// </summary>
31+
private async Task<string?> ForceRefreshTokenAsync()
32+
{
33+
try
34+
{
35+
// 通过请求新的 token 来触发 refresh token 流程
36+
// 这会在后端更新用户的 claims
37+
var refreshTokenResult = await _accessTokenProvider.RequestAccessToken(new AccessTokenRequestOptions
38+
{
39+
Scopes = new List<string> { "openid", "profile", "offline_access" }
40+
});
41+
42+
if (refreshTokenResult.TryGetToken(out var newToken))
43+
{
44+
_logger.LogInformation("Token 刷新成功");
45+
return newToken.Value;
46+
}
47+
48+
_logger.LogWarning("无法获取有效的 token,需要重新登录");
49+
return null;
50+
}
51+
catch (Exception ex)
52+
{
53+
_logger.LogError(ex, "强制刷新 token 时发生错误");
54+
return null;
55+
}
1956
}
2057

21-
/// <summary>
22-
/// 在 WASM 模式下设置团队后,获取最新的身份验证状态
58+
/// <summary>
59+
/// 在 WASM 模式下设置团队后,通过 refresh token 获取最新的身份验证状态
2360
/// </summary>
2461
public async Task SetCurrentTeamAsync(Guid teamId)
2562
{
2663
try
2764
{
28-
// 在 WASM 模式下,最可靠的方式是直接刷新页面
29-
// 因为 RequestAccessToken() 通常只返回缓存的 token,不会真正刷新
30-
// 而团队信息的更新需要服务端重新颁发包含最新 claims 的 token
31-
65+
_logger.LogInformation("开始切换团队,团队ID: {TeamId}", teamId);
66+
3267
// 短暂延迟确保后端团队信息更新完成
3368
await Task.Delay(100);
34-
35-
// 直接使用页面刷新,这是最可靠的方式
36-
// 页面刷新会重新初始化 OIDC 客户端,获取最新的 token 和 claims
37-
_navigationManager.NavigateTo(_navigationManager.Uri, true);
69+
70+
// 强制刷新 token,获取最新的 claims
71+
var newToken = await ForceRefreshTokenAsync();
72+
73+
if (newToken != null)
74+
{
75+
_logger.LogInformation("团队切换完成,团队ID: {TeamId}", teamId);
76+
}
77+
else
78+
{
79+
// 如果 token 刷新失败,回退到页面刷新
80+
_logger.LogWarning("Token 刷新失败,回退到页面刷新");
81+
_navigationManager.NavigateTo(_navigationManager.Uri, true);
82+
}
3883
}
39-
catch (Exception)
84+
catch (Exception ex)
4085
{
41-
// 确保在任何异常情况下都能刷新页面
42-
_navigationManager.NavigateTo(_navigationManager.Uri, true);
86+
_logger.LogError(ex, "切换团队时发生错误,团队ID: {TeamId}", teamId);
4387
}
4488
}
4589

@@ -58,9 +102,9 @@ public async Task<Guid> GetCurrentTeamAsync()
58102
return teamId;
59103
}
60104
}
61-
catch (Exception)
105+
catch (Exception ex)
62106
{
63-
// 如果获取失败,返回空的 GUID
107+
_logger.LogError(ex, "获取当前团队ID时发生错误");
64108
}
65109

66110
return Guid.Empty;

tests/MasaWasmApp/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ await builder.AddMasaOpenIdConnectAsync(new MasaOpenIdConnectOptions
1111
{
1212
Authority = masaStackConfig.GetSsoDomain(),
1313
ClientId = masaStackConfig.GetWebId(MasaStackProject.Auth),
14-
Scopes = new List<string> { "openid", "profile" }
14+
Scopes = new List<string> { "openid", "profile", "offline_access" }
1515
});
1616

1717
builder.Services.AddMasaStackComponent(MasaStackProject.Auth, "", microFrontend: false);

0 commit comments

Comments
 (0)