web-dev-qa-db-ja.com

OpenIDConnectを介してAzureADからユーザーのメールアドレスを取得します

Office 365アカウントを使用して自分のサイトでユーザーを認証しようとしているので、OWIN OpenID Connectミドルウェアを使用して認証を追加するためのガイダンスに従い、ユーザーのプロファイルの認証と取得に成功しました。

現在、ユーザーの電子メールアドレスを取得しようとしています(システムアカウントに連絡先の詳細を入力できるように)が、電子メールの要求を取り戻すことができないようです。スコープを使ってリクエストしてみましたopenid profile emailですが、クレームセットにはメール情報が含まれていません。

OpenID Connectエンドポイントを介してAzureADからユーザーの電子メールを取得する方法はありますか?

14
Paul Turner

私は解決策にたどり着く前に、同じ問題に数日間苦労しました。あなたの質問への回答:はい、あなたが次のことをしている限り、あなたはあなたの主張で電子メールアドレスを取り戻すことができるはずです:

  1. リクエストにprofileまたはemailスコープを含め、
  2. Azure Portal Active Directoryセクションで、サインインしてユーザープロファイルを読み取る委任されたアクセス許可の下に含めるようにアプリケーションを構成します。

電子メールアドレスはemailクレームで返されない場合があることに注意してください。私の場合(機能するようになったら)、nameクレームで返されます。

ただし、電子メールアドレスが戻らないまったくは、次のいずれかの問題が原因である可能性があります。

AzureADアカウントに関連付けられている電子メールアドレスがありません

このガイドに従って Azure Active Directory v2.0エンドポイントのスコープ、アクセス許可、および同意emailスコープを含めても、電子メールアドレスが返されない場合があります:

emailクレームは、電子メールアドレスがユーザーアカウントに関連付けられている場合にのみトークンに含まれますが、常にそうであるとは限りません。 emailスコープを使用する場合、アプリはemailクレームがトークンに存在しない場合を処理できるように準備する必要があります。

他のプロファイル関連のクレーム(_given_name_や_family_name_など)が返される場合は、これが問題である可能性があります。

ミドルウェアによって破棄されたクレーム

これが私の原因でした。 anyプロファイル関連のクレーム(名、姓、ユーザー名、電子メールなど)が返されませんでした。

私の場合、ID処理スタックは次のようになります。

問題はIdentityServer3.AspNetIdentityAspNetIdentityUserServiceクラスにありました: 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);
}
_

クレームコレクションを渡し、無視することに注意してください。私の解決策は、これから派生したクラスを作成し、メソッドを次のようにオーバーライドすることでした。

_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オブジェクトに追加するだけです。

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

も参照してください

12
Mark Whitaker

サインイン要求で&resource = https://graph.windows.net を承認エンドポイントに渡してから、Azure AD GraphAPIに認証済みの組織ユーザーのOfficeを照会するオプションはありますか? 365の電子メールアドレス?たとえば、GET https://graph.windows.net/me/mail?api-version=1.5

追加のリファレンスについては、AzureADSamplesGitHubのWebApp-WebAPI-MultiTenant-OpenIdConnect-DotNetコードサンプルを参照してください。

3
Zion Brewer

私は何日も同じ問題に苦しんでいました...私は個人のMicrosoftアカウントを持つユーザーから電子メールアドレスを取得していましたが、会社のMicrosoftアカウントを持つユーザーからは取得していませんでした。

個人アカウントの場合、電子メールアドレスは予想どおりemailフィールドに返されます。

会社のアカウントの場合、メールアドレスはpreferred_usernameフィールドに返されます。

私がまだ発見していない別のマイクロソフトのバリエーションがないことを私の指を交差させ続けます...

2
gaefan

2019年の更新された回答:emailクレームは、リクエストに含まれない可能性のあるオプションのクレームです( ソース

管理対象ユーザー(テナント内のユーザー)の場合は、このオプションのクレームを介して、またはv2.0の場合のみOpenIDスコープを使用して要求する必要があります。

次のように、Azure Portalのマニフェストファイルを更新して、オプションのクレームを含める必要があります。

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

この回答は部分的に このブログ投稿 に触発されました。

1
mai

同じ状況で、ログイン後にアクセス可能なすべてのユーザークレームを返す非常に単純なコードになりました(電子メールを含む)

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];
        }
    }
}
1
pau Fer