我使用内置的“配置Azure AD身份验证”功能配置了我的MVC webapp,它为我提供了以下代码:
public async Task<string> GetTokenForApplication()
{
string signedInUserID = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value;
string tenantID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;
string userObjectID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
// get a token for the Graph without triggering any user interaction (from the cache, via multi-resource refresh token, etc)
ClientCredential clientcred = new ClientCredential(clientId, appKey);
// initialize AuthenticationContext with the token cache of the currently signed in user, as kept in the app's database
AuthenticationContext authenticationContext = new AuthenticationContext(aadInstance + tenantID, new ADALTokenCache(signedInUserID));
AuthenticationResult authenticationResult = await authenticationContext.AcquireTokenSilentAsync(graphResourceID, clientcred, new UserIdentifier(userObjectID, UserIdentifierType.UniqueId));
return authenticationResult.AccessToken;
}
继承模特
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
}
public override void DeleteItem(TokenCacheItem item)
{
base.DeleteItem(item);
}
}
的DbContext:
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext()
: base("AzureDatabase")
{
}
public DbSet<UserTokenCache> UserTokenCacheList { get; set; }
}
public class UserTokenCache
{
[Key]
public int UserTokenCacheId { get; set; }
public string webUserUniqueId { get; set; }
public byte[] cacheBits { get; set; }
public DateTime LastWrite { get; set; }
}
首先,所有令牌缓存都存储在由连接到名为“defaultconnection”的数据库的函数自动配置的本地数据库中。然而,当我试图发布我的网络应用程序时,我遇到了错误,我意识到这是因为所有令牌都存储在本地。所以我尝试将DBContext迁移到我的Azure数据库。我迁移后,我一直得到这个例外。有没有办法解决这个问题?
答案 0 :(得分:0)
根据我的理解,我们应该在调用AcquireTokenSilentAsync
方法之前执行获取令牌而不使用刷新令牌。
例如,我们可以在用户登录后获取授权码后获取令牌。以下是一段代码供您参考:
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = SettingsHelper.ClientId,
Authority = SettingsHelper.Authority,
Notifications = new OpenIdConnectAuthenticationNotifications()
{
//
// If there is a code in the OpenID Connect response, redeem it for an access token and refresh token, and store those away.
AuthorizationCodeReceived = (context) =>
{
var code = context.Code;
ClientCredential credential = new ClientCredential(SettingsHelper.ClientId, SettingsHelper.ClientSecret);
String UserObjectId = context.AuthenticationTicket.Identity.FindFirst(ClaimTypes.NameIdentifier).Value;
AuthenticationContext authContext = new AuthenticationContext(SettingsHelper.Authority, new ADALTokenCache(UserObjectId));
authContext.AcquireTokenByAuthorizationCode(code, new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)), credential, SettingsHelper.AADGraphResourceId);
//authContext.TokenCache.Clear();
return Task.FromResult(0);
}
}
});
您可以参考此方案的完整代码示例here以使用AcquireTokenSilentAsync
函数。