1
+ using Microsoft . AspNetCore . Components . WebAssembly . Authentication ;
2
+
1
3
namespace Masa . Stack . Components . Infrastructure . Identity ;
2
4
3
5
/// <summary>
4
6
/// WASM 模式的团队状态管理器
5
- /// 在 WASM 模式下,通过页面刷新获取包含最新团队信息的 token
6
- /// 经测试发现 RequestAccessToken() 只返回缓存的 token,不会真正刷新,所以使用页面刷新确保可靠性
7
+ /// 在 WASM 模式下,通过 refresh token 获取包含最新团队信息的 token
7
8
/// </summary>
8
9
public class WasmTeamStateManager : ITeamStateManager , IScopedDependency
9
10
{
10
11
private readonly AuthenticationStateProvider _authenticationStateProvider ;
11
12
private readonly NavigationManager _navigationManager ;
13
+ private readonly IAccessTokenProvider _accessTokenProvider ;
14
+ private readonly ILogger < WasmTeamStateManager > _logger ;
12
15
13
16
public WasmTeamStateManager (
14
17
AuthenticationStateProvider authenticationStateProvider ,
15
- NavigationManager navigationManager )
18
+ NavigationManager navigationManager ,
19
+ IAccessTokenProvider accessTokenProvider ,
20
+ ILogger < WasmTeamStateManager > logger )
16
21
{
17
22
_authenticationStateProvider = authenticationStateProvider ;
18
23
_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
+ }
19
56
}
20
57
21
- /// <summary>
22
- /// 在 WASM 模式下设置团队后,获取最新的身份验证状态
58
+ /// <summary>
59
+ /// 在 WASM 模式下设置团队后,通过 refresh token 获取最新的身份验证状态
23
60
/// </summary>
24
61
public async Task SetCurrentTeamAsync ( Guid teamId )
25
62
{
26
63
try
27
64
{
28
- // 在 WASM 模式下,最可靠的方式是直接刷新页面
29
- // 因为 RequestAccessToken() 通常只返回缓存的 token,不会真正刷新
30
- // 而团队信息的更新需要服务端重新颁发包含最新 claims 的 token
31
-
65
+ _logger . LogInformation ( "开始切换团队,团队ID: {TeamId}" , teamId ) ;
66
+
32
67
// 短暂延迟确保后端团队信息更新完成
33
68
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
+ }
38
83
}
39
- catch ( Exception )
84
+ catch ( Exception ex )
40
85
{
41
- // 确保在任何异常情况下都能刷新页面
42
- _navigationManager . NavigateTo ( _navigationManager . Uri , true ) ;
86
+ _logger . LogError ( ex , "切换团队时发生错误,团队ID: {TeamId}" , teamId ) ;
43
87
}
44
88
}
45
89
@@ -58,9 +102,9 @@ public async Task<Guid> GetCurrentTeamAsync()
58
102
return teamId ;
59
103
}
60
104
}
61
- catch ( Exception )
105
+ catch ( Exception ex )
62
106
{
63
- // 如果获取失败,返回空的 GUID
107
+ _logger . LogError ( ex , "获取当前团队ID时发生错误" ) ;
64
108
}
65
109
66
110
return Guid . Empty ;
0 commit comments