SQL Server令牌缓存问题

时间:2018-07-24 14:20:38

标签: c# entity-framework azure azure-active-directory powerbi

我基本上是从https://github.com/Azure-Samples/active-directory-dotnet-webapp-webapi-multitenant-openidconnect/blob/master/TodoListWebApp/DAL/EFADALTokenCache.cs这里获取代码的,但是它不适合我的应用程序,因为我不需要示例中给出的每个用户的缓存。因此,我删除了接受User作为参数的构造函数,因为我希望缓存是全局的。我想出了这个版本:

 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
        }
}

您认为这可以用作全局缓存吗?还是它有问题,并且必须始终如示例中所述基于用户?

另一个查询是为什么要在Clear()中清除数据库。这是否意味着每当应用程序池关闭或我的数据库将被清除时?但这不应该发生。

感谢您的帮助。

1 个答案:

答案 0 :(得分:1)

如果您尝试实现全局令牌缓存而不考虑用户,那么我会看到您的代码有问题,因为代码正在为每个登录用户寻找任何现有的缓存 由于代码使用webUserUniqueId进行过滤

_TestEntities.TestTokenCaches.FirstOrDefault(c => c.webUserUniqueId == args.DisplayableId);

在正确的示例代码中,每个用户都有一组保存在数据库(或作为集合)中的令牌,因此,当他们登录Web应用程序时,他们可以直接执行其Web API调用,而无需重新调用-验证/重复同意。

我不确定为什么要这样做,但是我认为如果要为Web实现自定义令牌缓存,最好为不同的用户登录提供理想的令牌隔离级别。

此外,Clear()方法通过删除db中的所有项目来清除缓存,但是GitHub示例中尚未调用此方法,您需要从SignOut()方法添加对authContext.TokenCache.clear()的调用的AccountController清除用户注销时的缓存。