@@ -34,31 +34,27 @@ namespace Microsoft.Identity.Web.Client.TokenCacheProviders
34
34
/// An implementation of token cache for both Confidential and Public clients backed by MemoryCache.
35
35
/// MemoryCache is useful in Api scenarios where there is no HttpContext.Session to cache data.
36
36
/// </summary>
37
- /// <seealso cref="https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/ token-cache-serialization"/>
37
+ /// <seealso cref="https://aka.ms/msal-net- token-cache-serialization"/>
38
38
public class MSALPerUserMemoryTokenCacheProvider : IMSALUserTokenCacheProvider
39
39
{
40
40
/// <summary>
41
41
/// The backing MemoryCache instance
42
42
/// </summary>
43
43
internal IMemoryCache memoryCache ;
44
44
45
- /// <summary>
46
- /// The internal handle to the client's instance of the Cache
47
- /// </summary>
48
- private ITokenCache UserTokenCache ;
45
+ private readonly MSALMemoryTokenCacheOptions CacheOptions ;
49
46
50
47
/// <summary>
51
- /// Once the user signes in, this will not be null and can be ontained via a call to Thread.CurrentPrincipal
48
+ /// Enables the singleton object to access the right HttpContext
52
49
/// </summary>
53
- internal ClaimsPrincipal SignedInUser ;
54
-
55
- private readonly MSALMemoryTokenCacheOptions CacheOptions ;
50
+ private IHttpContextAccessor httpContextAccessor ;
56
51
57
52
/// <summary>Initializes a new instance of the <see cref="MSALPerUserMemoryTokenCache"/> class.</summary>
58
53
/// <param name="cache">The memory cache instance</param>
59
- public MSALPerUserMemoryTokenCacheProvider ( IMemoryCache cache , MSALMemoryTokenCacheOptions option )
54
+ public MSALPerUserMemoryTokenCacheProvider ( IMemoryCache cache , MSALMemoryTokenCacheOptions option , IHttpContextAccessor httpContextAccessor )
60
55
{
61
56
this . memoryCache = cache ;
57
+ this . httpContextAccessor = httpContextAccessor ;
62
58
63
59
if ( option != null )
64
60
{
@@ -76,70 +72,17 @@ public MSALPerUserMemoryTokenCacheProvider(IMemoryCache cache, MSALMemoryTokenCa
76
72
/// <param name="user">The signed-in user for whom the cache needs to be established. Not needed by all providers.</param>
77
73
public void Initialize ( ITokenCache tokenCache , HttpContext httpcontext , ClaimsPrincipal user )
78
74
{
79
- this . SignedInUser = user ;
80
-
81
- this . UserTokenCache = tokenCache ;
82
- this . UserTokenCache . SetBeforeAccess ( this . UserTokenCacheBeforeAccessNotification ) ;
83
- this . UserTokenCache . SetAfterAccess ( this . UserTokenCacheAfterAccessNotification ) ;
84
- this . UserTokenCache . SetBeforeWrite ( this . UserTokenCacheBeforeWriteNotification ) ;
85
-
86
- if ( this . SignedInUser == null )
87
- {
88
- // No users signed in yet, so we return
89
- return ;
90
- }
91
-
92
- this . LoadUserTokenCacheFromMemory ( ) ;
93
- }
94
-
95
- /// <summary>
96
- /// Explores the Claims of a signed-in user (if available) to populate the unique Id of this cache's instance.
97
- /// </summary>
98
- /// <returns>The signed in user's object.tenant Id , if available in the ClaimsPrincipal.Current instance</returns>
99
- internal string GetMsalAccountId ( )
100
- {
101
- if ( this . SignedInUser != null )
102
- {
103
- return this . SignedInUser . GetMsalAccountId ( ) ;
104
- }
105
- return null ;
106
- }
107
-
108
- /// <summary>Loads the user token cache from memory.</summary>
109
- private void LoadUserTokenCacheFromMemory ( )
110
- {
111
- string cacheKey = this . GetMsalAccountId ( ) ;
112
-
113
- if ( string . IsNullOrWhiteSpace ( cacheKey ) )
114
- return ;
115
-
116
- byte [ ] tokenCacheBytes = ( byte [ ] ) this . memoryCache . Get ( this . GetMsalAccountId ( ) ) ;
117
- this . UserTokenCache . DeserializeMsalV3 ( tokenCacheBytes ) ;
118
- }
119
-
120
- /// <summary>
121
- /// Persists the user token blob to the memoryCache.
122
- /// </summary>
123
- private void PersistUserTokenCache ( )
124
- {
125
- string cacheKey = this . GetMsalAccountId ( ) ;
126
-
127
- if ( string . IsNullOrWhiteSpace ( cacheKey ) )
128
- return ;
129
-
130
- // Ideally, methods that load and persist should be thread safe.MemoryCache.Get() is thread safe.
131
- this . memoryCache . Set ( this . GetMsalAccountId ( ) , this . UserTokenCache . SerializeMsalV3 ( ) , this . CacheOptions . AbsoluteExpiration ) ;
75
+ tokenCache . SetBeforeAccess ( this . UserTokenCacheBeforeAccessNotification ) ;
76
+ tokenCache . SetAfterAccess ( this . UserTokenCacheAfterAccessNotification ) ;
77
+ tokenCache . SetBeforeWrite ( this . UserTokenCacheBeforeWriteNotification ) ;
132
78
}
133
79
134
80
/// <summary>
135
81
/// Clears the TokenCache's copy of this user's cache.
136
82
/// </summary>
137
- public void Clear ( )
83
+ public void Clear ( string accountId )
138
84
{
139
- this . memoryCache . Remove ( this . GetMsalAccountId ( ) ) ;
140
-
141
- // Nulls the currently deserialized instance
142
- this . LoadUserTokenCacheFromMemory ( ) ;
85
+ this . memoryCache . Remove ( accountId ) ;
143
86
}
144
87
145
88
/// <summary>
@@ -148,12 +91,21 @@ public void Clear()
148
91
/// <param name="args">Contains parameters used by the MSAL call accessing the cache.</param>
149
92
private void UserTokenCacheAfterAccessNotification ( TokenCacheNotificationArgs args )
150
93
{
151
- this . SetSignedInUserFromNotificationArgs ( args ) ;
152
-
153
94
// if the access operation resulted in a cache update
154
95
if ( args . HasStateChanged )
155
96
{
156
- this . PersistUserTokenCache ( ) ;
97
+ string cacheKey = args . Account ? . HomeAccountId ? . Identifier ;
98
+ if ( string . IsNullOrEmpty ( cacheKey ) )
99
+ {
100
+ cacheKey = httpContextAccessor . HttpContext . User . GetMsalAccountId ( ) ;
101
+ }
102
+
103
+ if ( string . IsNullOrWhiteSpace ( cacheKey ) )
104
+ return ;
105
+
106
+ // Ideally, methods that load and persist should be thread safe.MemoryCache.Get() is thread safe.
107
+ this . memoryCache . Set ( cacheKey , args . TokenCache . SerializeMsalV3 ( ) , this . CacheOptions . AbsoluteExpiration ) ;
108
+
157
109
}
158
110
}
159
111
@@ -164,7 +116,17 @@ private void UserTokenCacheAfterAccessNotification(TokenCacheNotificationArgs ar
164
116
/// <param name="args">Contains parameters used by the MSAL call accessing the cache.</param>
165
117
private void UserTokenCacheBeforeAccessNotification ( TokenCacheNotificationArgs args )
166
118
{
167
- this . LoadUserTokenCacheFromMemory ( ) ;
119
+ string cacheKey = args . Account ? . HomeAccountId ? . Identifier ;
120
+ if ( string . IsNullOrEmpty ( cacheKey ) )
121
+ {
122
+ cacheKey = httpContextAccessor . HttpContext . User . GetMsalAccountId ( ) ;
123
+ }
124
+
125
+ if ( string . IsNullOrWhiteSpace ( cacheKey ) )
126
+ return ;
127
+
128
+ byte [ ] tokenCacheBytes = ( byte [ ] ) this . memoryCache . Get ( cacheKey ) ;
129
+ args . TokenCache . DeserializeMsalV3 ( tokenCacheBytes , shouldClearExistingCache : true ) ;
168
130
}
169
131
170
132
/// <summary>
@@ -174,18 +136,5 @@ private void UserTokenCacheBeforeAccessNotification(TokenCacheNotificationArgs a
174
136
private void UserTokenCacheBeforeWriteNotification ( TokenCacheNotificationArgs args )
175
137
{
176
138
}
177
-
178
- /// <summary>
179
- /// To keep the cache, ClaimsPrincipal and Sql in sync, we ensure that the user's object Id we obtained by MSAL after
180
- /// successful sign-in is set as the key for the cache.
181
- /// </summary>
182
- /// <param name="args">Contains parameters used by the MSAL call accessing the cache.</param>
183
- private void SetSignedInUserFromNotificationArgs ( TokenCacheNotificationArgs args )
184
- {
185
- if ( this . SignedInUser == null && args . Account != null )
186
- {
187
- this . SignedInUser = args . Account . ToClaimsPrincipal ( ) ;
188
- }
189
- }
190
139
}
191
140
}
0 commit comments