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

时间:2023-02-18
本文介绍了通过 OpenID Connect 从 Azure AD 获取用户的电子邮件地址的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

问题描述

我正在尝试使用他们的 Office 365 帐户对我的站点的用户进行身份验证,因此我一直在遵循有关使用 OWIN OpenID Connect 中间件添加身份验证的指南,并成功地验证并检索了他们的个人资料.

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

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

解决方案

我在同一个问题上苦苦挣扎了几天才找到解决方案.回答您的问题:是的,只要您:

  1. 在您的请求中包含 profileemail 范围,并且
  2. 在 Azure 门户 Active Directory 部分中配置您的应用程序,以在 委派权限 下包含登录和读取用户配置文件.

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

但是,根本没有得到电子邮件地址可能是由以下问题之一引起的:

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

根据本指南 Azure Active Directory v2.0 端点中的范围、权限和同意,即使您包含 email 范围,您也可能无法获得电子邮件地址:p><块引用>

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

如果您收到其他与个人资料相关的声明(如 given_namefamily_name),这可能是问题所在.

中间件丢弃的声明

这就是我的原因.我没有收到任何与个人资料相关的声明(名字、姓氏、用户名、电子邮件等).

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

  • IdentityServer3
  • IdentityServer3.AspNetIdentity
  • 基于 couchbase-aspnet-identity
  • 的自定义 Couchbase 存储提供程序

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

另见

  • 这篇文章由 Scott Brady 撰写 包含有关声明转换的部分,如果上述方法均未修复它,这可能很有用.
  • 关于 IdentityServer3 GitHub 帐户的讨论 对我帮助很大,尤其是 此回复.

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:

  1. Include the profile or email scope in your request, and
  2. Configure your application in the Azure Portal Active Directory section to include Sign in and read user profile under 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.

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

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 email claim is included in a token only if an email address is associated with the user account, which is not always the case. 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.

If you're getting other profile-related claims back (like given_name and family_name), this might be the problem.

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:

  • IdentityServer3
  • IdentityServer3.AspNetIdentity
  • A custom Couchbase storage provider based on couchbase-aspnet-identity

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

See also

  • 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.

这篇关于通过 OpenID Connect 从 Azure AD 获取用户的电子邮件地址的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

上一篇:现有 Asp.Net 核心应用程序中缺少 Azure Active Directory 连接服务的身份验证 下一篇:如何在 Visual Studio 2017 项目(新的 .csproj 文件格式)中设置“OutputPath&quo

相关文章

最新文章