我正在尝试使用他们的 Office 365 帐户对我的站点的用户进行身份验证,因此我一直在遵循有关使用 OWIN OpenID Connect 中间件添加身份验证的指南,并成功地验证并检索了他们的个人资料.
我现在正在尝试获取用户的电子邮件地址(以便我可以使用他们的联系方式填充他们的系统帐户),但我似乎无法收到电子邮件声明.我尝试使用范围 openid profile email
发出请求,但声明集不包含任何邮件信息.
有没有办法通过 OpenID Connect 端点从 Azure AD 获取用户的电子邮件?
我在同一个问题上苦苦挣扎了几天才找到解决方案.回答您的问题:是的,只要您:
profile
或 email
范围,并且请注意,电子邮件地址可能不会在 email
声明中返回:在我的情况下(一旦我让它工作)它会在 name
声明中返回.
但是,根本没有得到电子邮件地址可能是由以下问题之一引起的:
根据本指南 Azure Active Directory v2.0 端点中的范围、权限和同意,即使您包含 email
范围,您也可能无法获得电子邮件地址:p><块引用>
email
声明仅在电子邮件地址与用户帐户相关联时包含在令牌中,但情况并非总是如此.如果它使用 email
范围,您的应用应该准备好处理令牌中不存在 email
声明的情况.
如果您收到其他与个人资料相关的声明(如 given_name
和 family_name
),这可能是问题所在.
这就是我的原因.我没有收到任何与个人资料相关的声明(名字、姓氏、用户名、电子邮件等).
在我的例子中,身份处理堆栈如下所示:
问题出在 IdentityServer3.AspNetIdentity AspNetIdentityUserService
类中:InstantiateNewUserFromExternalProviderAsync()
方法如下所示:
受保护的虚拟任务<TUser>InstantiateNewUserFromExternalProviderAsync(字符串提供者,字符串 providerId,IEnumerable<Claim>索赔){var user = new TUser() { UserName = Guid.NewGuid().ToString("N") };返回 Task.FromResult(user);}
注意它会传入一个声明集合然后忽略它.我的解决方案是创建一个派生自此的类并将该方法重写为如下所示:
受保护的覆盖任务<TUser>InstantiateNewUserFromExternalProviderAsync(字符串提供者,字符串 providerId,IEnumerable<Claim>索赔){var user = 新的 TUser{用户名 = Guid.NewGuid().ToString("N"),索赔=索赔};返回 Task.FromResult(user);}
我不确切知道您正在使用什么中间件组件,但很容易看到从您的外部提供商返回的原始声明;这至少会告诉您他们恢复正常,并且问题出在您的中间件的某个地方.只需将 Notifications
属性添加到您的 OpenIdConnectAuthenticationOptions
对象,如下所示:
//将 Azure AD 配置为提供程序var azureAdOptions = 新的 OpenIdConnectAuthenticationOptions{AuthenticationType = 常量.Azure.AuthenticationType,标题 = Resources.AzureSignInCaption,范围 = 常量.Azure.Scopes,ClientId = Config.Azure.ClientId,权限 = 常量.Azure.AuthenticationRootUri,PostLogoutRedirectUri = Config.Identity.RedirectUri,RedirectUri = Config.Azure.PostSignInRedirectUri,AuthenticationMode = AuthenticationMode.Passive,TokenValidationParameters = 新的 TokenValidationParameters{验证发行人 = 假},通知 = 新的 OpenIdConnectAuthenticationNotifications{AuthorizationCodeReceived = 上下文 =>{//记录 Azure AD 返回的所有声明var 声明 = context.AuthenticationTicket.Identity.Claims;foreach(声明中的 var 声明){Log.Debug("{0} = {1}", claim.Type, claim.Value);}返回空值;}},SignInAsAuthenticationType = signInAsType//这必须在 TokenValidationParameters 之后};app.UseOpenIdConnectAuthentication(azureAdOptions);
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.
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.
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
or email
scope in your request, andNote 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:
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
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:
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);
}
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:
// 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);
这篇关于通过 OpenID Connect 从 Azure AD 获取用户的电子邮件地址的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!