我尝试使用他们的Office 365帐户对我的网站的用户进行身份验证,因此我一直遵循使用OWIN OpenID Connect中间件添加身份验证的指导,并成功管理以验证和检索他们的个人资料。
我现在正在尝试获取用户的电子邮件地址(因此我可以使用他们的联系人详细信息填充他们的系统帐户),但我似乎无法收到电子邮件索赔。我尝试使用范围openid profile email
发出请求,但声明集不包含任何邮件信息。
有没有办法通过OpenID Connect端点从Azure AD获取用户的电子邮件?
答案 0 :(得分:11)
在达成解决方案之前,我在几天内遇到了同样的问题。在回答您的问题时:是的,您应该能够在您的索赔中找到电子邮件地址:
profile
或email
范围,请注意,email
声明中可能不会返回电子邮件地址:在我的情况下(一旦我开始工作),它将返回name
声明。
但是,没有收到所有的电子邮件地址可能是由以下问题之一引起的:
根据Scopes, permissions, and consent in the Azure Active Directory v2.0 endpoint的指南,即使您包含email
范围,您也可能无法收到电子邮件地址:
仅当电子邮件地址与用户帐户相关联时,
如果您收到其他与个人资料相关的声明(例如given_name
和family_name
),则可能是问题所在。
这是我的原因。我没有收到任何与个人资料相关的声明(名字,姓氏,用户名,电子邮件等)。
就我而言,身份处理堆栈如下所示:
问题在于IdentityServer3.AspNetIdentity AspNetIdentityUserService
类:InstantiateNewUserFromExternalProviderAsync()
method looks like this:
protected virtual Task<TUser> InstantiateNewUserFromExternalProviderAsync(
string provider,
string providerId,
IEnumerable<Claim> claims)
{
var user = new TUser() { UserName = Guid.NewGuid().ToString("N") };
return Task.FromResult(user);
}
请注意,它会传入声明集合,然后忽略它。我的解决方案是创建一个派生自此的类,并将方法重写为:
protected override Task<TUser> InstantiateNewUserFromExternalProviderAsync(
string provider,
string providerId,
IEnumerable<Claim> claims)
{
var user = new TUser
{
UserName = Guid.NewGuid().ToString("N"),
Claims = claims
};
return Task.FromResult(user);
}
我不确切知道您正在使用哪些中间件组件,但很容易看到外部提供商返回的原始声明;那至少会告诉你他们回来了,问题出在中间件的某个地方。只需向Notifications
对象添加OpenIdConnectAuthenticationOptions
属性,如下所示:
// Configure Azure AD as a provider
var azureAdOptions = new OpenIdConnectAuthenticationOptions
{
AuthenticationType = Constants.Azure.AuthenticationType,
Caption = Resources.AzureSignInCaption,
Scope = Constants.Azure.Scopes,
ClientId = Config.Azure.ClientId,
Authority = Constants.Azure.AuthenticationRootUri,
PostLogoutRedirectUri = Config.Identity.RedirectUri,
RedirectUri = Config.Azure.PostSignInRedirectUri,
AuthenticationMode = AuthenticationMode.Passive,
TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false
},
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthorizationCodeReceived = context =>
{
// Log all the claims returned by Azure AD
var claims = context.AuthenticationTicket.Identity.Claims;
foreach (var claim in claims)
{
Log.Debug("{0} = {1}", claim.Type, claim.Value);
}
return null;
}
},
SignInAsAuthenticationType = signInAsType // this MUST come after TokenValidationParameters
};
app.UseOpenIdConnectAuthentication(azureAdOptions);
答案 1 :(得分:3)
是否可以选择将登录请求中的&amp; resource = https://graph.windows.net传递给授权端点,然后在Azure AD Graph API中查询经过身份验证的组织用户的Office 365电子邮件地址?例如,GET https://graph.windows.net/me/mail?api-version=1.5
有关其他参考,请参阅AzureADSamples GitHub上的WebApp-WebAPI-MultiTenant-OpenIdConnect-DotNet代码示例。
答案 2 :(得分:2)
我几天来一直在努力解决同样的问题......我从个人微软账户的用户那里获得了电子邮件地址,但没有那些拥有微软公司账号的用户。
对于个人帐户,电子邮件地址会在email
字段中返回,就像人们期望的那样。
对于公司帐户,电子邮件地址将在preferred_username
字段中返回。
保持我的手指交叉,我还没有发现另一个微软的变种...
答案 3 :(得分:1)
在相同的情况下,我最终得到了一个非常简单的代码,该代码返回了登录后所有可访问的用户声明(包括电子邮件)
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using Microsoft.AspNetCore.Mvc;
namespace Controllers
{
public class BaseController : Controller
{
protected string GetCurrentUserIDFromClaims()
{
return User.FindFirstValue(ClaimTypes.NameIdentifier);
}
protected List<string> AllClaimsFromAzure()
{
ClaimsIdentity claimsIdentity = ((ClaimsIdentity)User.Identity);
return claimsIdentity.Claims.Select(x => x.Value).ToList();
}
protected string GetCurrentEmailFromAzureClaims()
{
return AllClaimsFromAzure()[3];
}
}
}
答案 4 :(得分:0)
2019年更新的答案:email
声明是可选的声明,可能不包含在请求中(Source)
对于受管用户(租户内部的用户),必须通过此可选声明或仅在v2.0上使用OpenID范围来请求它。
您必须在Azure门户中更新清单文件以包括可选声明,如下所示:
"optionalClaims": {
"idToken": [
{
"name": "email",
"source": null,
"essential": false,
"additionalProperties": []
}
],
}
此答案部分受this blog post的启发。