Azure Active Directory 身份验证损坏 - 没有已知的根本原因

Azure Active Directory Auth Broken - No known root cause

我正在构建一个依赖于 AAD 身份验证的 ASP.NET MVC 网络应用程序。我使用标准流程向项目添加身份验证(通过 VS 进行 AAD 身份验证),并且在过去两周内运行良好。

今天突然坏了:

这发生在 ADALTokenCache 初始化(标准 AAD 身份验证例程)时:

public ADALTokenCache(string signedInUserId)
{ 
    // associate the cache to the current user of the web app
    userId = signedInUserId;
    this.AfterAccess = AfterAccessNotification;
    this.BeforeAccess = BeforeAccessNotification;
    this.BeforeWrite = BeforeWriteNotification;
    // look up the entry in the database
    Cache = db.UserTokenCacheList.FirstOrDefault(c => c.webUserUniqueId == userId);
    // place the entry in memory
    this.Deserialize((Cache == null) ? null : MachineKey.Unprotect(Cache.cacheBits,"ADALCache"));
}

看起来很奇怪,我也不知道根本原因——除了添加更多视图和控制器(没有任何东西应该与身份验证混淆)之外,应用程序本身没有做任何更改。

清除浏览器 cookie 没有任何作用。手动设置 MachineKey 也无济于事。

部署应用程序后,此重现会在本地和远程服务器上进行。

有人遇到过这个吗?

在不对配置进行任何修改的情况下看起来很奇怪。

解决这个问题的方法是删除数据库。

缓存基于本地MDF文件,并在Web.config中更改其名称:

<add name="DefaultConnection" 
connectionString="Data Source=(LocalDb)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\aspnet-Den-SomeNewName.mdf;Initial Catalog=aspnet-Den-SomeNewName;Integrated Security=True" 
providerName="System.Data.SqlClient" />

当我收到此错误时,是因为我缓存了一些错误的登录信息并且身份验证正在努力检索它,从而导致异常。

为了解决这个问题,我从 SSMS 中删除了数据库,然后注释掉了以下行:

<add name="DefaultConnection" 
connectionString="Data Source=(LocalDb)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\aspnet-Den-SomeNewName.mdf;Initial Catalog=aspnet-Den-SomeNewName;Integrated Security=True" 
providerName="System.Data.SqlClient" /> 

在 Web.config.

然后右键单击您的解决方案并配置您的 Azure AD 身份验证。单击完成以使用与之前相同的设置重新配置它。因为您注释掉了默认连接,它会自动为您生成一个新字符串,并为您的会员信息创建一个新的本地数据库,并清除缓存。

之前的解决方案对我不起作用,但这个对我有用!

我遇到了同样的问题。

清除 UserTokenCaches Table 而不是删除整个数据库。

我认为 Visual Studio 自动生成的 ADALTokenCache class 的默认实现中存在错误。据我所知,WebUserUniqueId 列上没有 UNIQUE 约束,在从缓存中检索令牌的 .FirstOrDefault(c => c.WebUserUniqueId == userId) 调用中没有 .OrderByDesc(t=>t.LastWriteDate),也没有清除发生的缓存。换句话说,可以针对 AAD 进行多次身份验证,并且每次都可以将新令牌写入数据库中的 UserTokenCaches table,但是当调用 .FirstOrDefault() 时在没有排序的情况下检索令牌,无法确定检索到哪个版本,并且根据 SQL 服务器通常写入数据的方式,更有可能从 table 检索到最旧的令牌。

此错误还可能导致 invalid_grant 消息 (AADSTS70002) 指出 刷新由于不活动,令牌已过期。令牌是在 ... 上发布的,并且在 ...

期间处于非活动状态

恢复和 运行ning 的最快方法是清除数据库中的 UserTokenCaches table 并让您的用户针对 Azure 重新进行身份验证,或者至少,运行 a DELETE UserTokenCaches WHERE LastWriteDate < ... 以摆脱一些最旧的标记。

快速而肮脏的解决方法是在创建 AuthenticationContext 和 [=23 的代码行之前,在 Startup.Auth.cs 中的方法中清除用户令牌的缓存=] 对象。

db.UserTokenCacheList.RemoveRange(db.UserTokenCacheList.Where(t => t.webUserUniqueId == signedInUserID));
db.SaveChanges();

UserTokenCaches table 的默认实现及其构建方式可能存在可伸缩性问题。 webUserUniqueId 的默认类型是 NVARCHAR(MAX) 并且不能在其上放置 UNIQUE 或索引约束。我建议将类型更改为 VARCHAR 并更改其长度以正确保存值,并在此列上创建单个 UNIQUE CLUSTERED 索引,因为 cacheBits 列不能包含在小覆盖中指数。最好也限制 cacheBits 列的大小,尽管我不知道这个列或 webUserUniqueId 列可以增长到多大。我也不知道如果数据类型从 NVARCHAR 更改为 VARCHAR 可能会如何影响从 .Net 通过 EF 的查找,因为我已经看到自动生成的基于 WHERE 的搜索将参数提升为 NVARCHAR 而不是 VARCHAR 导致 INDEX SCAN 或 TABLE SCAN 操作而不是 SEEK 操作。我不会调用 .FirstOrDefault(...),而是手动优化使用 db.UserTokenCacheList.FirstOrDefault(...) 的调用,以确保使用正确的索引。 (以下代码未经测试):

Cache = db.UserTokenCacheList.SqlQuery("SELECT * FROM UserTokenCacheList WHERE webUniqueUserId = @webUniqueUserId;", new System.Data.SqlClient.SqlParameter("@webUniqueUserId", System.Data.SqlDbType.VarChar({Value=signedInUserID}).FirstOrDefault();