简体   繁体   English

通过OpenID Connect从Azure AD获取用户的email地址

[英]Get the user's email address from Azure AD via OpenID Connect

I'm trying to authenticate users to my site with their Office 365 accounts, so I have been following the guidance on using the OWIN OpenID Connect middleware to add authentication and successfully managed to authenticate and retrieve their profile.我正在尝试使用他们的 Office 365 帐户对访问我网站的用户进行身份验证,因此我一直在遵循有关使用 OWIN OpenID Connect 中间件添加身份验证的指南,并成功地设法对他们的个人资料进行身份验证和检索。

I am now trying to get the email address of the user (so I can populate their system account with their contact details), but I can't seem to get an email claim back.我现在正在尝试获取用户的 email 地址(这样我就可以用他们的联系方式填充他们的系统帐户),但我似乎无法获得 email 的索赔。 I have tried making a request using the scope openid profile email , but the claim-set does not contain any mail information.我尝试使用 scope openid profile email发出请求,但声明集不包含任何邮件信息。

Is there a way to get the email of a user from Azure AD via the OpenID Connect endpoint?有没有办法通过 OpenID Connect 端点从 Azure AD 获取用户的 email?

I struggled with the same problem for a few days before arriving at a solution.在找到解决方案之前,我在同样的问题上挣扎了几天。 In answer to your question: yes, you should be able to get the e-mail address back in your claims as long as you:回答您的问题:是的,您应该能够在索赔中取回电子邮件地址,只要您:

  1. Include the profile or email scope in your request, and在您的请求中包含profileemail范围,以及
  2. Configure your application in the Azure Portal Active Directory section to include Sign in and read user profile under Delegated Permissions .在 Azure 门户 Active Directory 部分配置您的应用程序,以在Delegated Permissions下包含登录和读取用户配置文件

Note that the e-mail address may not be returned in an email claim: in my case (once I got it working) it's coming back in a name claim.请注意,电子邮件地址可能不会在email声明中返回:在我的情况下(一旦我开始工作),它会在name声明中返回。

However, not getting the e-mail address back at all could be caused by one of the following issues:然而,没有得到所有的电子邮件地址回可以通过下列问题之一引起:

No e-mail address associated with the Azure AD account没有与 Azure AD 帐户关联的电子邮件地址

As per this guide to Scopes, permissions, and consent in the Azure Active Directory v2.0 endpoint , even if you include the email scope you may not get an e-mail address back:根据Azure Active Directory v2.0 端点中的范围、权限和同意指南,即使您包含email范围,您也可能无法获得电子邮件地址:

The email claim is included in a token only if an email address is associated with the user account, which is not always the case.仅当电子邮件地址与用户帐户相关联时, email声明才包含在令牌中,但情况并非总是如此。 If it uses the email scope, your app should be prepared to handle a case in which the email claim does not exist in the token.如果它使用email范围,您的应用程序应该准备好处理令牌中不存在email声明的情况。

If you're getting other profile-related claims back (like given_name and family_name ), this might be the problem.如果您收到其他与个人资料相关的声明(如given_namefamily_name ),这可能是问题所在。

Claims discarded by middleware中间件丢弃的声明

This was the cause for me.这就是我的原因。 I wasn't getting any profile-related claims back (first name, last name, username, e-mail, etc.).我没有收到任何与个人资料相关的声明(名字、姓氏、用户名、电子邮件等)。

In my case, the identity-handling stack looks like this:就我而言,身份处理堆栈如下所示:

The problem was in the IdentityServer3.AspNetIdentity AspNetIdentityUserService class: the InstantiateNewUserFromExternalProviderAsync() method looks like this :问题出在 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);
}

Note it passes in a claims collection then ignores it.注意它传入一个声明集合然后忽略它。 My solution was to create a class derived from this and override the method to something like this:我的解决方案是创建一个派生自此的类并将该方法覆盖为如下所示:

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);
}

I don't know exactly what middleware components you're using, but it's easy to see the raw claims returned from your external provider;我不知道您正在使用哪些中间件组件,但是很容易看到从您的外部提供程序返回的原始声明; that'll at least tell you they're coming back OK and that the problem is somewhere in your middleware.这至少会告诉你他们回来了,问题出在你的中间件中。 Just add a Notifications property to your OpenIdConnectAuthenticationOptions object, like this:只需将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);

See also也可以看看

I was struggling with the same issue for days... I was getting the email address from users with personal Microsoft accounts but not for those with company Microsoft accounts.我在同一个问题上苦苦挣扎了好几天……我从拥有个人 Microsoft 帐户的用户那里获取电子邮件地址,但没有从拥有公司 Microsoft 帐户的用户那里获取电子邮件地址。

For personal accounts, the email address is returned in an email field like one would expect.对于个人帐户,电子邮件地址在email字段中返回,就像人们所期望的那样。

For company accounts, the email address is returned in a preferred_username field.对于公司帐户,电子邮件地址在preferred_username字段中返回。

Keeping my fingers crossed that there isn't another Microsoft variation that I haven't discovered yet...保持我的手指交叉,没有另一个我还没有发现的微软变体......

Is it an option for you to pass &resource= https://graph.windows.net in the sign-in request to the authorization endpoint, then query the Azure AD Graph API for the authenticated organizational user's Office 365 email address?是否可以选择将登录请求中的 &resource= https://graph.windows.net传递给授权终结点,然后查询 Azure AD Graph API 以获取经过身份验证的组织用户的 Office 365 电子邮件地址? For example, GET https://graph.windows.net/me/mail?api-version=1.5例如,GET https://graph.windows.net/me/mail?api-version=1.5

For additional reference, see the WebApp-WebAPI-MultiTenant-OpenIdConnect-DotNet code sample on the AzureADSamples GitHub.有关其他参考,请参阅 AzureADSamples GitHub 上的 WebApp-WebAPI-MultiTenant-OpenIdConnect-DotNet 代码示例。

Updated answer for 2019: email claim is an optional claim that might be not included in the request ( Source ) 2019 年更新答案: email声明是一个可选声明,可能不包含在请求中( 来源

For managed users (those inside the tenant), it must be requested through this optional claim or, on v2.0 only, with the OpenID scope.对于托管用户(租户内部的用户),必须通过此可选声明或仅在 v2.0 上使用 OpenID 范围来请求。

You have to update the manifest file in the Azure Portal to include optional claim, like so:您必须更新 Azure 门户中的清单文件以包含可选声明,如下所示:

"optionalClaims": {
    "idToken": [
        {
            "name": "email",
            "source": null,
            "essential": false,
            "additionalProperties": []
        }
    ],
}

This answer was partially inspired by this blog post .这个答案的部分灵感来自这篇博文

in the same situation I ended up with a very simple code that return all the user claims accesible after login (including email)在同样的情况下,我最终得到了一个非常简单的代码,该代码在登录后返回所有用户声明(包括电子邮件)

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];
        }
    }
}

Get the upn value from the user's claims:从用户声明中获取upn值:

var userClaims = User.Identity as System.Security.Claims.ClaimsIdentity;
string email = userClaims?.FindFirst(System.Security.Claims.ClaimTypes.Upn)?.Value;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 使用OpenId Connect与Azure AD然后模拟现有的身份用户 - Using OpenId Connect with Azure AD then impersonate an existing Identity User 使用 DotNetOpenAuth 从 OpenID Provider 获取 email 地址 - Get email address from OpenID Provider with DotNetOpenAuth openid connect owin 如何验证来自 Azure AD 的令牌? - How does the openid connect owin validate the token from Azure AD? 我们可以在Azure AD B2C中的“配置文件编辑策略”中更改用户的电子邮件地址吗? - Can we change email address of user from “Profile editing policies” in Azure AD B2C? OpenID:尝试从Google OP获取电子邮件地址 - OpenID: Trying to Get Email Address from Google OP 获取广告组用户的电子邮件 - Get AD Group User's email 使用OpenId与Azure AD连接时如何将用户令牌发送到浏览器? - How to send user token to browser when using OpenId connect with Azure AD? 从Azure AD Connect获取身份令牌 - Get the identity token from Azure AD Connect 使用C#和OAuth从Twitter获取用户的电子邮件地址 - Get user's email address from Twitter with C# and OAuth 从.NET通过email地址搜索AD用户的正确方法 - Correct method to search for AD user by email address from .NET
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM