SQL Server Tokencache issue

99封情书 提交于 2020-01-06 06:57:08

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!