问题
I basically took code from here https://github.com/Azure-Samples/active-directory-dotnet-webapp-webapi-multitenant-openidconnect/blob/master/TodoListWebApp/DAL/EFADALTokenCache.cs but it is not suitable for my application as I don't need the cache per user as given in the example. Accordingly I removed the constructor that accepted User as a parameter since I wanted the cache to be global. I have came up with this version:
public class EFTestTokenCache : TokenCache
{
private TestEntities _TestEntities = new TestEntities();
private TestTokenCache _cache;
public EFTestTokenCache()
{
this.AfterAccess = AfterAccessNotification;
this.BeforeAccess = BeforeAccessNotification;
this.BeforeWrite = BeforeWriteNotification;
}
// clean up the DB
public override void Clear()
{
base.Clear();
foreach (var cacheEntry in _TestEntities.TestTokenCaches)
_TestEntities.TestTokenCaches.Remove(cacheEntry);
_TestEntities.SaveChanges();
}
// Notification raised before ADAL accesses the cache.
// This is your chance to update the in-memory copy from the DB, if the in-memory version is stale
void BeforeAccessNotification(TokenCacheNotificationArgs args)
{
if (_cache == null)
{
// first time access
_cache = _TestEntities.TestTokenCaches.FirstOrDefault(c => c.webUserUniqueId == args.DisplayableId);
}
else
{ // retrieve last write from the DB
var status = from e in _TestEntities.TestTokenCaches
where (e.webUserUniqueId == args.DisplayableId)
select new
{
LastWrite = e.LastWrite
};
// if the in-memory copy is older than the persistent copy
if (status.First().LastWrite > _cache.LastWrite)
//// read from from storage, update in-memory copy
{
_cache = _TestEntities.TestTokenCaches.FirstOrDefault(c => c.webUserUniqueId == args.DisplayableId);
}
}
this.Deserialize((_cache == null) ? null : _cache.cacheBits);
}
// Notification raised after ADAL accessed the cache.
// If the HasStateChanged flag is set, ADAL changed the content of the cache
void AfterAccessNotification(TokenCacheNotificationArgs args)
{
// if state changed
if (this.HasStateChanged)
{
if (_cache != null)
{
_cache.cacheBits = this.Serialize();
_cache.LastWrite = DateTime.Now;
}
else
{
_cache = new TestTokenCache
{
webUserUniqueId = args.DisplayableId,
cacheBits = this.Serialize(),
LastWrite = DateTime.Now
};
}
// update the DB and the lastwrite
_TestEntities.Entry(_cache).State = _cache.EntryId == 0 ? EntityState.Added : EntityState.Modified;
_TestEntities.SaveChanges();
this.HasStateChanged = false;
}
}
void BeforeWriteNotification(TokenCacheNotificationArgs args)
{
// if you want to ensure that no concurrent write take place, use this notification to place a lock on the entry
}
}
Do you think this would work fine as a global cache or is it buggy and always has to be user based as given in the example?
Another query is why is the database cleared in Clear()
. Does this mean whenever application pool shuts down or so my database would be cleared? That should not happen though.
Any help is appreciated.
回答1:
If you are trying to implement a global token cache irrespective of the user then I see an issue with your code as code is looking for any existing cache per the sign in user as code is using webUserUniqueId to filter
_TestEntities.TestTokenCaches.FirstOrDefault(c => c.webUserUniqueId == args.DisplayableId);
In the correct sample code, every user has a set of tokens that are saved in a DB (or as collection), so that when they sign in to the web app they can directly perform their web API calls without having to re-authenticate/repeat consent.
I am not sure of the purpose why you want to do this but in my opinion if you are implementing a custom token cache for a web it would be good to provide the desirable level of isolation between tokens for different users signing in.
Also, Clear() method clears the cache by deleting all the items in db but this method has not been called in the GitHub sample and you need to add a call to authContext.TokenCache.clear() from SignOut() method of AccountController to clear the cache on user signout.
来源:https://stackoverflow.com/questions/51501050/sql-server-tokencache-issue