通过OpenID Connect从Azure AD获取用户的电子邮件地址 [英] Get the user's email address from Azure AD via OpenID Connect
问题描述
我正尝试使用其Office 365帐户对用户进行身份验证,因此我一直遵循有关使用OWIN 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.
我现在正在尝试获取用户的电子邮件地址(以便我可以用他们的联系方式填充他们的系统帐户),但是我似乎无法找回电子邮件声明.我尝试使用范围openid profile email
发出请求,但是声明集不包含任何邮件信息.
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. I have tried making a request using the scope openid profile email
, but the claim-set does not contain any mail information.
是否可以通过OpenID Connect终结点从Azure AD获取用户的电子邮件?
Is there a way to get the email of a user from Azure AD via the OpenID Connect endpoint?
推荐答案
在解决问题之前,我为同一问题苦苦挣扎了几天.为回答您的问题:是的,只要您满足以下条件,您就应该能够在索赔中重新获得该电子邮件地址:
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
或email
范围,并且 - 在"Azure门户活动目录"部分中配置您的应用程序,以在"委派的权限" 下包括"登录并读取用户配置文件".
- Include the
profile
oremail
scope in your request, and - Configure your application in the Azure Portal Active Directory section to include Sign in and read user profile under Delegated Permissions.
请注意,在email
声明中可能不会返回该电子邮件地址:就我而言(一旦我工作了),它在name
声明中又回来了.
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.
但是,由于以下问题之一,可能导致根本无法恢复电子邮件地址 :
However, not getting the e-mail address back at all could be caused by one of the following issues:
按照 Azure Active Directory v2.0终结点中的范围,权限和同意,即使您包括了email
范围,也可能无法找回电子邮件地址:
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:
仅当电子邮件地址与用户帐户相关联时,
The
如果您要找回其他与个人资料相关的声明(例如given_name
和family_name
),则可能是问题所在.
If you're getting other profile-related claims back (like given_name
and family_name
), this might be the problem.
这是我的原因.我没有得到与个人资料相关的任何声明(名字,姓氏,用户名,电子邮件等).
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:
- IdentityServer3
- IdentityServer3.AspNetIdentity
- 基于 couchbase-aspnet-identity 的自定义Couchbase存储提供程序
- IdentityServer3
- IdentityServer3.AspNetIdentity
- A custom Couchbase storage provider based on couchbase-aspnet-identity
问题出在IdentityServer3.AspNetIdentity AspNetIdentityUserService
类中:
The problem was in the IdentityServer3.AspNetIdentity AspNetIdentityUserService
class: the 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);
}
请注意,它传递了Claims集合,然后将其忽略.我的解决方案是创建一个由此类派生的类,并将该方法重写为类似这样的方法:
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);
}
我不知道您使用的是什么中间件组件,但是很容易看到您的外部提供程序返回的原始声明.至少会告诉您他们回来了,而且问题出在中间件中.只需将Notifications
属性添加到您的OpenIdConnectAuthenticationOptions
对象,如下所示:
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:
// 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);
另请参见
- Scott Brady的这篇文章包含有关索赔转换"的部分,如果以上两个方法都无法解决,可能会很有用.
- 有关IdentityServer3 GitHub帐户的讨论对我有很大帮助,尤其是此回复.
- This article by Scott Brady contains a section on Claims Transformation which may be useful if neither of the above fixes it.
- This discussion on the IdentityServer3 GitHub account was a huge help to me, especially this response.
See also
这篇关于通过OpenID Connect从Azure AD获取用户的电子邮件地址的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!