Azure AD SSO в ASP.NET - Как обновить токен в автоматическом режиме? - PullRequest
0 голосов
/ 05 ноября 2019

У меня довольно простой проект ASP.NET, в котором установлена ​​аутентификация Azure AD. Он использует CookieAuthentication по умолчанию и использует единый вход Azure AD для входа в систему.

Поэтому я не могу понять, что если я войду в систему и оставлю страницу открытой в течение 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);
        }
    }
});

Это 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);
        }
    }

Эточто я пробовал, но не работает. Буду признателен за любую помощь. Заранее спасибо.

...