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