[英]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:回答您的问题:是的,您应该能够在索赔中取回电子邮件地址,只要您:
profile
or email
scope in your request, and在您的请求中包含profile
或email
范围,以及 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:然而,没有得到所有的电子邮件地址回可以通过下列问题之一引起:
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
If you're getting other profile-related claims back (like given_name
and family_name
), this might be the problem.如果您收到其他与个人资料相关的声明(如given_name
和family_name
),这可能是问题所在。
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);
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.