通过OpenID Connect从Azure AD获取用户的电子邮件地址

Pau*_*ner 14 c# owin azure-active-directory openid-connect

我正在尝试使用他们的Office 365帐户对我的站点的用户进行身份验证,因此我一直遵循使用OWIN OpenID Connect中间件添加身份验证的指导,并成功管理以验证和检索其配置文件.

我现在正在尝试获取用户的电子邮件地址(因此我可以使用他们的联系人详细信息填充他们的系统帐户),但我似乎无法收到电子邮件索赔.我尝试使用作用域发出请求openid profile email,但声明集不包含任何邮件信息.

有没有办法通过OpenID Connect端点从Azure AD获取用户的电子邮件?

Mar*_*ker 11

在达成解决方案之前,我在几天内遇到了同样的问题.在回答您的问题时:是的,您应该能够在您的索赔中找到电子邮件地址,只要您:

  1. 在您的请求中包含profileemail范围,以及
  2. 在Azure门户Active Directory部分中配置您的应用程序,以包括登录和读取委派权限下的用户配置文件.

请注意,email索赔中可能不会返回电子邮件地址:在我的情况下(一旦我开始工作),它就会在name索赔中返回.

然而,没有得到回E-mail地址可以通过下列问题之一引起:

没有与Azure AD帐户关联的电子邮件地址

根据Azure Active Directory v2.0端点中的范围,权限和许可指南,即使您包含email范围,也可能无法获得电子邮件地址:

email要求被包含在只有一个电子邮件地址与用户帐户,这是情况并非总是如此关联的令牌.如果它使用email范围,您的应用程序应准备好处理email令牌中不存在声明的情况.

如果您正在收到其他与个人资料相关的声明(例如given_namefamily_name),则可能是问题所在.

中间件丢弃的声明

这是我的原因.我没有得到任何与个人资料相关的声明(名字,姓氏,用户名,电子邮件等).

在我的例子中,身份处理堆栈如下所示:

问题出在IdentityServer3.AspNetIdentity AspNetIdentityUserService类中:InstantiateNewUserFromExternalProviderAsync()方法如下所示:

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);
}
Run Code Online (Sandbox Code Playgroud)

请注意,它会传入声明集合,然后忽略它.我的解决方案是创建一个派生自此的类,并将方法重写为如下所示:

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);
}
Run Code Online (Sandbox Code Playgroud)

我不确切知道您正在使用哪些中间件组件,但很容易看到从您的外部提供商返回的原始声明; 那至少会告诉你他们回来了,问题出在中间件的某个地方.只需NotificationsOpenIdConnectAuthenticationOptions对象添加属性,如下所示:

// 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);
Run Code Online (Sandbox Code Playgroud)

也可以看看


gae*_*fan 6

我在同一个问题上苦苦挣扎了好几天……我从拥有个人 Microsoft 帐户的用户那里获取电子邮件地址,但没有从拥有公司 Microsoft 帐户的用户那里获取电子邮件地址。

对于个人帐户,电子邮件地址会在您email期望的字段中返回。

对于公司帐户,电子邮件地址在preferred_username字段中返回。

保持我的手指交叉,没有另一个我还没有发现的微软变体......