首页 文章

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

提问于
浏览
13

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

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

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

3 回答

  • 2

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

    • 在您的请求中包含 profileemail 范围,以及

    • 在Azure门户Active Directory部分中配置您的应用程序,以包括登录和读取委派权限下的用户配置文件 .

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

    但是,完全没有收回电子邮件地址可能是由以下问题之一引起的:

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

    根据Scopes, permissions, and consent in the Azure Active Directory v2.0 endpoint的指南,即使您包含 email 范围,您也可能无法收到电子邮件地址:

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

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

    中间件丢弃的声明

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

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

    问题出在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);
    }
    

    我没有't know exactly what middleware components you'重新使用,但它至少告诉你他们回来了,问题就在你的中间件的某个地方 . 只需将 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);
    

    另见

  • 3

    是否可以选择将登录请求中的&resource = https://graph.windows.net传递给授权 endpoints ,然后在Azure AD Graph API中查询经过身份验证的组织用户的Office 365电子邮件地址?例如,GET https://graph.windows.net/me/mail?api-version=1.5

    有关其他参考,请参阅AzureADSamples GitHub上的WebApp-WebAPI-MultiTenant-OpenIdConnect-DotNet代码示例 .

  • 7

    几天我一直在努力解决同样的问题......我从个人微软账户的用户那里获得了电子邮件地址,但是那些拥有微软公司账号的用户却没有 .

    对于个人帐户,电子邮件地址会在 email 字段中返回,就像人们期望的那样 .

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

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

相关问题