c# - SQL Server 令牌缓存问题
问题描述
我基本上从这里获取代码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()
. 这是否意味着每当应用程序池关闭或我的数据库将被清除?但这不应该发生。
任何帮助表示赞赏。
解决方案
如果您尝试实现与用户无关的全局令牌缓存,那么我会看到您的代码存在问题,因为代码正在为每个登录用户查找任何现有缓存,因为代码正在使用 webUserUniqueId 进行过滤
_TestEntities.TestTokenCaches.FirstOrDefault(c => c.webUserUniqueId == args.DisplayableId);
在正确的示例代码中,每个用户都有一组保存在数据库(或作为集合)中的令牌,因此当他们登录到 Web 应用程序时,他们可以直接执行 Web API 调用,而无需重新验证/重复同意。
我不确定您为什么要这样做,但在我看来,如果您正在为 Web 实现自定义令牌缓存,最好为登录的不同用户提供所需的令牌之间的隔离级别。
此外,Clear() 方法通过删除 db 中的所有项目来清除缓存,但在 GitHub 示例中尚未调用此方法,您需要从 AccountController 的 SignOut() 方法中添加对 authContext.TokenCache.clear() 的调用以在用户注销时清除缓存。
推荐阅读
- c++ - 如何捕获或记录内存释放错误?
- python - 制作三角形最简单的方法是什么
- ios - “Runner”需要配置文件。在签名和功能编辑器中选择配置文件
- mysql - sum 子查询返回多于 1 行,但不是作为独立查询
- ruby-on-rails - 从免费 Heroku Redis 计划升级到第一个付费层后,我们的应用程序崩溃并且无法运行
- javascript - 不理解 api 响应 (FRONTEND MENTOR)
- vb.net - ListViewGroup 显示项目但不显示标题
- amazon-web-services - .aws 目录在哪里?
- node.js - 是否可以同时运行多个不同的 pm2 实例?
- json - 具有重复键的 Python3 JSON 解析