ASP.NET中的Azure AD SSO-如何以静默方式更新令牌?

ASP.NET中的Azure AD SSO-如何以静默方式更新令牌?,asp.net,azure-active-directory,asp.net-identity,owin,Asp.net,Azure Active Directory,Asp.net Identity,Owin,我有一个非常简单的ASP.NET项目,安装了Azure AD身份验证。 默认情况下,它使用CookieAuthentication,并使用Azure AD SSO登录 所以我不能理解的是,如果我登录并让页面打开1小时——这是Azure AD访问令牌到期时间,它就会停止工作 为了避免这种情况,我尝试在访问令牌过期之前以静默方式更新它,但失败了。 甚至不知道为什么应用程序停止工作,因为它使用Cookie进行授权,并且只使用Azure AD登录进行身份验证 app.UseCookieAuthentic

我有一个非常简单的ASP.NET项目,安装了Azure AD身份验证。 默认情况下,它使用CookieAuthentication,并使用Azure AD SSO登录

所以我不能理解的是,如果我登录并让页面打开1小时——这是Azure AD访问令牌到期时间,它就会停止工作

为了避免这种情况,我尝试在访问令牌过期之前以静默方式更新它,但失败了。 甚至不知道为什么应用程序停止工作,因为它使用Cookie进行授权,并且只使用Azure AD登录进行身份验证

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    Provider = new CookieAuthenticationProvider
    {
        OnValidateIdentity = (context) =>
        {
            var threshold = DateTime.UtcNow.AddMinutes(55);

            if (context.Properties.ExpiresUtc < threshold)
            {
                var authManager = context.OwinContext.Authentication;

                string signedInUserID = context.Identity.FindFirst(System.IdentityModel.Claims.ClaimTypes.NameIdentifier).Value;

                if (authContext == null)
                    authContext = new AuthenticationContext(Authority, new ADALTokenCache(signedInUserID));

                ClientCredential credential = new ClientCredential(clientId, appKey);
                try
                {
                    var result = authContext.AcquireTokenSilentAsync(graphResourceId, clientId).Result;
                }
                catch (AggregateException ex)
                {
                    if (ex.InnerException.GetType() == typeof(AdalSilentTokenAcquisitionException))
                    {
                        var result = authContext.AcquireTokenAsync(graphResourceId, credential).Result;
                    }
                }
            }

            return Task.FromResult(0);
        }
    }
});
这是我尝试过的,但不起作用。 非常感谢您的帮助。
提前感谢。

建议您在该处理程序中使用async并等待。使用.Result可能会导致各种“有趣”的bug。将处理程序指定为
async(context)=>
,并在异步函数调用之前使用
wait
。然后,您可以删除
返回任务。FromResult()
谢谢,@juunas。我尝试了async/await,但得到了相同的错误。奇怪的是,AcquireTokenSilentAsync和AcquireTokenAsync函数在令牌过期前正常工作,但在令牌过期后停止工作。听起来您的令牌缓存没有正常工作。你能分享你的
ADALTokenCache
吗?我在问题中添加了TokenCache代码。实际上,默认情况下创建的是默认的ADALTokenCache。
public class ADALTokenCache : TokenCache
    {
        private ApplicationDbContext db = new ApplicationDbContext();
        private string userId;
        private UserTokenCache Cache;

        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"));
        }

        // Clean up the database
        public override void Clear()
        {
            base.Clear();
            var cacheEntry = db.UserTokenCacheList.FirstOrDefault(c => c.webUserUniqueId == userId);
            db.UserTokenCacheList.Remove(cacheEntry);
            db.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 = db.UserTokenCacheList.FirstOrDefault(c => c.webUserUniqueId == userId);
            }
            else
            {
                // Retrieve last write from the DB
                var status = from e in db.UserTokenCacheList
                             where (e.webUserUniqueId == userId)
                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 = db.UserTokenCacheList.FirstOrDefault(c => c.webUserUniqueId == userId);
                }
            }
            this.Deserialize((Cache == null) ? null : MachineKey.Unprotect(Cache.cacheBits, "ADALCache"));
        }

        // 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)
            {
                Cache = new UserTokenCache
                {
                    webUserUniqueId = userId,
                    cacheBits = MachineKey.Protect(this.Serialize(), "ADALCache"),
                    LastWrite = DateTime.Now
                };
                // Update the DB and the lastwrite
                db.Entry(Cache).State = Cache.UserTokenCacheId == 0 ? EntityState.Added : EntityState.Modified;
                db.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
            var t = args;
        }

        public override void DeleteItem(TokenCacheItem item)
        {
            base.DeleteItem(item);
        }
    }