ADAL - AcquireTokenSilentAsync 失败(Azure Active Directory 身份验证库)
ADAL - AcquireTokenSilentAsync fails (Azure Active Directory Authentication Libraries)
我写了一个新的应用程序通过其余的访问办公室数据API,所以我想使用新的
身份验证模型(V2.0 端点)
What's different about the v2.0 endpoit
我可以通过调用
获得令牌
private static string[] scopes = { "https://outlook.office.com/mail.read", "https://outlook.office.com/calendars.read" };
public async Task<ActionResult> SignIn()
{
... SNIP
Uri authUri = await authContext.GetAuthorizationRequestUrlAsync(scopes, null, clientId, redirectUri, new UserIdentifier("contoso@foo", UserIdentifierType.RequiredDisplayableId), null);
return Redirect(authUri.ToString());
}
authContext.AcquireTokenByAuthorizationCodeAsync(authCode, redirectUri, credential, scopes)
问题是第二次调用
public async Task<ActionResult> SignIn()
{
... SNIP
var authResult = authContext.AcquireTokenSilentAsync(scopes, clientId, new UserIdentifier("contoso@foo.ch", UserIdentifierType.RequiredDisplayableId))
}
返回的令牌确实包含 UniqueId,但此信息未存储在令牌对象中。 Token 的 UserInfo 始终为空。因为该字段为空,所以令牌缓存找不到令牌。
感谢您的提示和想法
返回令牌
{
"aud":"https://outlook.office.com",
"iss":"https://sts.windows.net/f2ac6f3f-3df0-4068-a677-e4dfdf924b2/",
"iat":146 dfdf21,
"nbf":146 dfdf4621,
"exp":1463 dfdf38521,
"acr":"1",
"amr":[
"pwd"
],
"appid":"b13dfdf9-0561-4dfdff5-945c-778dfdf0de5cd",
"appidacr":"1",
"family_name":"Pan",
"given_name":"Peter",
"ipaddr":"12.12.12.17",
"name":"Peter Pan",
"oid":"4b83dfdfdb-f6db-433e-b70a-2f9a6dbbeb48",
"puid":"100dfdfdfF5FBC",
"scp":"Calendars.Read Mail.Read Mail.ReadWrite",
"sub":"Z-chdfdsfnWqduUkCGZpsIdp-fdhpMMqqtwcHGs",
"tid":"f2ac6f3f-3560-4068-a677-e4bfe0c924b2",
"unique_name":"foo@contoso",
"upn":"foo@contoso",
"ver":"1.0"
}
类似问题:
Here
Microsoft 已删除 profile_info,您可以在此处阅读:
Important Updates to ADV2
目前图书馆有一个错误,因为它仍然检查它,如果它是空的,它不会 return 用户信息。
正确的信息在token_id...
Class:令牌响应
private AuthenticationResultEx GetResult(string token, string scope, long expiresIn)
{
DateTimeOffset expiresOn = (DateTimeOffset) (DateTime.UtcNow + TimeSpan.FromSeconds((double) expiresIn));
AuthenticationResult authenticationResult = new AuthenticationResult(this.TokenType, token, expiresOn);
ProfileInfo profileInfo = ProfileInfo.Parse(this.ProfileInfoString);
if (profileInfo != null)
{
string tenantId = profileInfo.TenantId;
string str1 = (string) null;
string str2 = (string) null;
if (!string.IsNullOrWhiteSpace(profileInfo.Subject))
str1 = profileInfo.Subject;
if (!string.IsNullOrWhiteSpace(profileInfo.PreferredUsername))
str2 = profileInfo.PreferredUsername;
authenticationResult.UpdateTenantAndUserInfo(tenantId, this.ProfileInfoString, new UserInfo()
{
UniqueId = str1,
DisplayableId = str2,
Name = profileInfo.Name,
Version = profileInfo.Version
});
}
return new AuthenticationResultEx()
{
Result = authenticationResult,
RefreshToken = this.RefreshToken,
ScopeInResponse = AdalStringHelper.CreateArrayFromSingleString(scope)
};
}
希望他们尽快修复,我也在等:-)
编辑:
我在这里发现了一些有趣的东西:
Dev Outlook get started
我已经说过,token_id中存储的所有信息,在上面的link中你可以阅读:
The prerelease version of ADAL v4 doesn't return the ID token directly, but it is accessible. The method included here is intended to work around this issue until ADAL is updated.
他们解释了一种访问令牌的方法:
private string GetUserEmail(AuthenticationContext context, string clientId)
{
// ADAL caches the ID token in its token cache by the client ID
foreach (TokenCacheItem item in context.TokenCache.ReadItems())
{
if (item.Scope.Contains(clientId))
{
return GetEmailFromIdToken(item.Token);
}
}
return string.Empty;
}
private string GetEmailFromIdToken(string token)
{
// JWT is made of three parts, separated by a '.'
// First part is the header
// Second part is the token
// Third part is the signature
string[] tokenParts = token.Split('.');
if (tokenParts.Length < 3)
{
// Invalid token, return empty
}
// Token content is in the second part, in urlsafe base64
string encodedToken = tokenParts[1];
// Convert from urlsafe and add padding if needed
int leftovers = encodedToken.Length % 4;
if (leftovers == 2)
{
encodedToken += "==";
}
else if (leftovers == 3)
{
encodedToken += "=";
}
encodedToken = encodedToken.Replace('-', '+').Replace('_', '/');
// Decode the string
var base64EncodedBytes = System.Convert.FromBase64String(encodedToken);
string decodedToken = System.Text.Encoding.UTF8.GetString(base64EncodedBytes);
// Load the decoded JSON into a dynamic object
dynamic jwt = Newtonsoft.Json.JsonConvert.DeserializeObject(decodedToken);
// User's email is in the preferred_username field
return jwt.preferred_username;
}
我还没有测试过这个,但是我会在我测试过后更新这个post,或者其他人会发表评论,如果他更快:-)
我写了一个新的应用程序通过其余的访问办公室数据API,所以我想使用新的 身份验证模型(V2.0 端点)
What's different about the v2.0 endpoit
我可以通过调用
获得令牌private static string[] scopes = { "https://outlook.office.com/mail.read", "https://outlook.office.com/calendars.read" };
public async Task<ActionResult> SignIn()
{
... SNIP
Uri authUri = await authContext.GetAuthorizationRequestUrlAsync(scopes, null, clientId, redirectUri, new UserIdentifier("contoso@foo", UserIdentifierType.RequiredDisplayableId), null);
return Redirect(authUri.ToString());
}
authContext.AcquireTokenByAuthorizationCodeAsync(authCode, redirectUri, credential, scopes)
问题是第二次调用
public async Task<ActionResult> SignIn()
{
... SNIP
var authResult = authContext.AcquireTokenSilentAsync(scopes, clientId, new UserIdentifier("contoso@foo.ch", UserIdentifierType.RequiredDisplayableId))
}
返回的令牌确实包含 UniqueId,但此信息未存储在令牌对象中。 Token 的 UserInfo 始终为空。因为该字段为空,所以令牌缓存找不到令牌。
感谢您的提示和想法
返回令牌
{
"aud":"https://outlook.office.com",
"iss":"https://sts.windows.net/f2ac6f3f-3df0-4068-a677-e4dfdf924b2/",
"iat":146 dfdf21,
"nbf":146 dfdf4621,
"exp":1463 dfdf38521,
"acr":"1",
"amr":[
"pwd"
],
"appid":"b13dfdf9-0561-4dfdff5-945c-778dfdf0de5cd",
"appidacr":"1",
"family_name":"Pan",
"given_name":"Peter",
"ipaddr":"12.12.12.17",
"name":"Peter Pan",
"oid":"4b83dfdfdb-f6db-433e-b70a-2f9a6dbbeb48",
"puid":"100dfdfdfF5FBC",
"scp":"Calendars.Read Mail.Read Mail.ReadWrite",
"sub":"Z-chdfdsfnWqduUkCGZpsIdp-fdhpMMqqtwcHGs",
"tid":"f2ac6f3f-3560-4068-a677-e4bfe0c924b2",
"unique_name":"foo@contoso",
"upn":"foo@contoso",
"ver":"1.0"
}
类似问题: Here
Microsoft 已删除 profile_info,您可以在此处阅读: Important Updates to ADV2
目前图书馆有一个错误,因为它仍然检查它,如果它是空的,它不会 return 用户信息。
正确的信息在token_id...
Class:令牌响应
private AuthenticationResultEx GetResult(string token, string scope, long expiresIn)
{
DateTimeOffset expiresOn = (DateTimeOffset) (DateTime.UtcNow + TimeSpan.FromSeconds((double) expiresIn));
AuthenticationResult authenticationResult = new AuthenticationResult(this.TokenType, token, expiresOn);
ProfileInfo profileInfo = ProfileInfo.Parse(this.ProfileInfoString);
if (profileInfo != null)
{
string tenantId = profileInfo.TenantId;
string str1 = (string) null;
string str2 = (string) null;
if (!string.IsNullOrWhiteSpace(profileInfo.Subject))
str1 = profileInfo.Subject;
if (!string.IsNullOrWhiteSpace(profileInfo.PreferredUsername))
str2 = profileInfo.PreferredUsername;
authenticationResult.UpdateTenantAndUserInfo(tenantId, this.ProfileInfoString, new UserInfo()
{
UniqueId = str1,
DisplayableId = str2,
Name = profileInfo.Name,
Version = profileInfo.Version
});
}
return new AuthenticationResultEx()
{
Result = authenticationResult,
RefreshToken = this.RefreshToken,
ScopeInResponse = AdalStringHelper.CreateArrayFromSingleString(scope)
};
}
希望他们尽快修复,我也在等:-)
编辑:
我在这里发现了一些有趣的东西: Dev Outlook get started
我已经说过,token_id中存储的所有信息,在上面的link中你可以阅读:
The prerelease version of ADAL v4 doesn't return the ID token directly, but it is accessible. The method included here is intended to work around this issue until ADAL is updated.
他们解释了一种访问令牌的方法:
private string GetUserEmail(AuthenticationContext context, string clientId)
{
// ADAL caches the ID token in its token cache by the client ID
foreach (TokenCacheItem item in context.TokenCache.ReadItems())
{
if (item.Scope.Contains(clientId))
{
return GetEmailFromIdToken(item.Token);
}
}
return string.Empty;
}
private string GetEmailFromIdToken(string token)
{
// JWT is made of three parts, separated by a '.'
// First part is the header
// Second part is the token
// Third part is the signature
string[] tokenParts = token.Split('.');
if (tokenParts.Length < 3)
{
// Invalid token, return empty
}
// Token content is in the second part, in urlsafe base64
string encodedToken = tokenParts[1];
// Convert from urlsafe and add padding if needed
int leftovers = encodedToken.Length % 4;
if (leftovers == 2)
{
encodedToken += "==";
}
else if (leftovers == 3)
{
encodedToken += "=";
}
encodedToken = encodedToken.Replace('-', '+').Replace('_', '/');
// Decode the string
var base64EncodedBytes = System.Convert.FromBase64String(encodedToken);
string decodedToken = System.Text.Encoding.UTF8.GetString(base64EncodedBytes);
// Load the decoded JSON into a dynamic object
dynamic jwt = Newtonsoft.Json.JsonConvert.DeserializeObject(decodedToken);
// User's email is in the preferred_username field
return jwt.preferred_username;
}
我还没有测试过这个,但是我会在我测试过后更新这个post,或者其他人会发表评论,如果他更快:-)