チュートリアル: Node.js Web アプリケーションに追加のサインインとサインアウトを追加する

このチュートリアルは、Node.js Web アプリの構築と、Microsoft Entra 管理センターを使用した認証の準備を行うシリーズの最終パートです。 このシリーズのパート 2 では、Node.js Web アプリを作成し、必要なすべてのファイルを整理しました。 このチュートリアルでは、Node.js Web アプリへのサインイン、サインアップ、サインアウトを追加します。 Node.js Web アプリへの認証の追加を簡略化するには、Node 用 Microsoft Authentication Library (MSAL) を使用します。 サインイン フローでは、ユーザーを安全にサインインする OpenID Connect (OIDC) 認証プロトコルが使用されます。

このチュートリアルでは、次のことについて説明します。

  • サインインロジックとサインアウトロジックを追加する
  • ID トークン要求を表示する
  • アプリを実行し、サインインとサインアウトのエクスペリエンスをテストします。

前提条件

MSAL 構成オブジェクトを作成する

コード エディターで authConfig.js ファイルを開き、次のコードを追加します。

require('dotenv').config();

const TENANT_SUBDOMAIN = process.env.TENANT_SUBDOMAIN || 'Enter_the_Tenant_Subdomain_Here';
const REDIRECT_URI = process.env.REDIRECT_URI || 'http://localhost:3000/auth/redirect';
const POST_LOGOUT_REDIRECT_URI = process.env.POST_LOGOUT_REDIRECT_URI || 'http://localhost:3000';

/**
 * Configuration object to be passed to MSAL instance on creation.
 * For a full list of MSAL Node configuration parameters, visit:
 * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-node/docs/configuration.md
 */
const msalConfig = {
    auth: {
        clientId: process.env.CLIENT_ID || 'Enter_the_Application_Id_Here', // 'Application (client) ID' of app registration in Azure portal - this value is a GUID
        authority: process.env.AUTHORITY || `https://${TENANT_SUBDOMAIN}.ciamlogin.com/`, // replace "Enter_the_Tenant_Subdomain_Here" with your tenant name
        clientSecret: process.env.CLIENT_SECRET || 'Enter_the_Client_Secret_Here', // Client secret generated from the app registration in Azure portal
    },
    system: {
        loggerOptions: {
            loggerCallback(loglevel, message, containsPii) {
                console.log(message);
            },
            piiLoggingEnabled: false,
            logLevel: 'Info',
        },
    },
};

module.exports = {
    msalConfig,
    REDIRECT_URI,
    POST_LOGOUT_REDIRECT_URI,
    TENANT_SUBDOMAIN
};

msalConfig オブジェクトには、認証フローの動作をカスタマイズするために使用する一連の構成オプションが含まれています。

authConfig.js ファイルで、次を置き換えます。

  • Enter_the_Application_Id_Here を、前に登録したアプリのアプリケーション (クライアント) ID に置き換えます。

  • Enter_the_Tenant_Subdomain_Here を、ディレクトリ (テナント) サブドメインに置き換えます。 たとえば、テナントのプライマリ ドメインが contoso.onmicrosoft.com の場合は、contoso を使用します。 テナント名がない場合は、テナントの詳細を読み取る方法を確認してください。

  • Enter_the_Client_Secret_Here を、前にコピーしたアプリ シークレットの値に置き換えます。

.env ファイルを使用して構成情報を格納する場合:

  1. コード エディターで .env ファイルを開き、次のコードを追加します。

        CLIENT_ID=Enter_the_Application_Id_Here
        TENANT_SUBDOMAIN=Enter_the_Tenant_Subdomain_Here
        CLIENT_SECRET=Enter_the_Client_Secret_Here
        REDIRECT_URI=http://localhost:3000/auth/redirect
        POST_LOGOUT_REDIRECT_URI=http://localhost:3000
    
  2. Enter_the_Application_Id_HereEnter_the_Tenant_Subdomain_HereEnter_the_Client_Secret_Here の各プレースホルダーを、上記の説明に沿って置き換えます。

authConfig.js ファイル内の変数msalConfigREDIRECT_URITENANT_SUBDOMAINPOST_LOGOUT_REDIRECT_URI 変数をエクスポートすると、ファイルが必要な場所でアクセスできるようになります。

カスタム URL ドメインを使用する (省略可能)

カスタム ドメインを使用して、認証 URL を完全にブランド化します。 ユーザーの視点から見ると、認証プロセスの間、ユーザーは ciamlogin.com ドメイン名にリダイレクトされず、あなたのドメインにとどまります。

カスタム ドメインを使用するには、以下の手順を実行します。

  1. 外部テナント内のアプリに対するカスタム URL ドメインの有効化」の手順を実行して、外部テナントに対してカスタム URL ドメインを有効にします。

  2. authConfig.js ファイルで、auth オブジェクトを見つけて、次のようにします。

    1. authority プロパティの値を https://Enter_the_Custom_Domain_Here/Enter_the_Tenant_ID_Here に更新します。 Enter_the_Custom_Domain_Here を実際のカスタム URL ドメインに、Enter_the_Tenant_ID_Here を実際のテナント ID に置き換えます。 テナント ID がわからない場合は、テナントの詳細を読み取る方法を確認してください。
    2. [Enter_the_Custom_Domain_Here] という値を持つ knownAuthorities プロパティを追加します。

authConfig.js ファイルを変更した後、カスタム URL ドメインが login.contoso.com で、テナント ID が aaaabbbb-0000-cccc-1111-dddd2222eeee であるとすると、ファイルは次のスニペットのようになるはずです。

//...
const msalConfig = {
    auth: {
        authority: process.env.AUTHORITY || 'https://login.contoso.com/aaaabbbb-0000-cccc-1111-dddd2222eeee', 
        knownAuthorities: ["login.contoso.com"],
        //Other properties
    },
    //...
};

Express Route を追加する

Express Route は、サインイン、サインアウト、ID トークン クレームの表示などの操作を実行できるようにするエンドポイントを提供します。

アプリのエントリ ポイント

コード エディターで "routes/index.js" ファイルを開き、次のコードを追加します。

const express = require('express');
const router = express.Router();

router.get('/', function (req, res, next) {
    res.render('index', {
        title: 'MSAL Node & Express Web App',
        isAuthenticated: req.session.isAuthenticated,
        username: req.session.account?.username !== '' ? req.session.account?.username : req.session.account?.name,
    });
});    
module.exports = router;

/ ルートは、アプリケーションへのエントリ ポイントです。 「アプリ UI コンポーネントをビルドする」で作成した views/index.hbs ビューがレンダリングされます。 isAuthenticated は、ビューに表示される内容を決定するブール変数です。

サインインとサインアウト

  1. コード エディターで routes/auth.js ファイルを開き、auth.js からコードを追加します。

  2. コード エディターで "controller/authController.js "ファイルを開き、それに authController.js からコードを追加します。

  3. コード エディターで、"auth/AuthProvider.js" ファイルを開き、それに AuthProvider.js からコードを追加します。

    /signin/signout、および /redirect ルートは routes/auth.js ファイルで定義されますが、そのロジックは auth/AuthProvider.js ファイルで実装します。

  • login メソッドにより、次のように /signin ルートが処理されます。

    • 認証コード フローの最初の区間がトリガーされ、サインイン フローが開始されます。

    • 前に作成した MSAL 構成オブジェクト msalConfig を使用して、機密クライアント アプリケーション インスタンスが初期化されます。

          const msalInstance = this.getMsalInstance(this.config.msalConfig);
      

      getMsalInstance メソッドは次のように定義されます。

          getMsalInstance(msalConfig) {
              return new msal.ConfidentialClientApplication(msalConfig);
          }
      
    • 承認コード フローの最初の区間で承認コード要求 URL を生成し、その URL にリダイレクトして承認コードを取得します。 この最初の区間は、redirectToAuthCodeUrl メソッドで実装されます。 ここでは、次のように MSAL の getAuthCodeUrl メソッドを使用して承認コード URL を生成しています。

      //...
      const authCodeUrlResponse = await msalInstance.getAuthCodeUrl(req.session.authCodeUrlRequest);
      //...
      

      次に、承認コード URL 自体にリダイレクトします。

      //...
      res.redirect(authCodeUrlResponse);
      //...
      
  • handleRedirect メソッドは、次のように /redirect ルートを処理します。

    • これは、前に「Web アプリを登録する」 で Microsoft Entra 管理センター内の Web アプリのリダイレクト URI として設定したものです。

    • このエンドポイントは、認証コード フローで使用する 2 番めの区間を実装します。 これは、認証コードを使用し、MSAL の acquireTokenByCode メソッドを使用して ID トークンを要求します。

      //...
      const tokenResponse = await msalInstance.acquireTokenByCode(authCodeRequest, req.body);
      //...
      
    • 応答を受け取ったら、Express セッションを作成し、必要な任意の情報をそこに格納できます。 isAuthenticated を含め、それを true に設定する必要があります。

      //...        
      req.session.idToken = tokenResponse.idToken;
      req.session.account = tokenResponse.account;
      req.session.isAuthenticated = true;
      //...
      
  • logout メソッドにより、次のように /signout ルートが処理されます。

    async logout(req, res, next) {
        /**
         * Construct a logout URI and redirect the user to end the
            * session with Azure AD. For more information, visit:
            * https://docs.microsoft.com/azure/active-directory/develop/v2-protocols-oidc#send-a-sign-out-request
            */
        const logoutUri = `${this.config.msalConfig.auth.authority}${TENANT_SUBDOMAIN}.onmicrosoft.com/oauth2/v2.0/logout?post_logout_redirect_uri=${this.config.postLogoutRedirectUri}`;
    
        req.session.destroy(() => {
            res.redirect(logoutUri);
        });
    }
    
    • サインアウト要求が開始されます。

    • ユーザーをアプリケーションからサインアウトさせる場合、ユーザーのセッションを終了するだけでは処理不足です。 ユーザーを logoutUri にリダイレクトする必要があります。 そうしないと、ユーザーは資格情報を再入力しなくても、アプリケーションに対して再認証できてしまう可能性があります。 テナントの名前が contoso の場合、logoutUrihttps://contoso.ciamlogin.com/contoso.onmicrosoft.com/oauth2/v2.0/logout?post_logout_redirect_uri=http://localhost:3000 のようになります。

ID トークン要求を表示する

コード エディターで routes/users.js ファイルを開き、次のコードを追加します。

const express = require('express');
const router = express.Router();

// custom middleware to check auth state
function isAuthenticated(req, res, next) {
    if (!req.session.isAuthenticated) {
        return res.redirect('/auth/signin'); // redirect to sign-in route
    }

    next();
};

router.get('/id',
    isAuthenticated, // check if user is authenticated
    async function (req, res, next) {
        res.render('id', { idTokenClaims: req.session.account.idTokenClaims });
    }
);        
module.exports = router;

ユーザーが認証されている場合、/id ルートに、views/id.hbs ビューを使用して ID トークン要求が表示されます。 このビューは、「アプリ UI コンポーネントをビルドする」で追加したものです。

given name などの特定の ID トークン要求を抽出するには:

const givenName = req.session.account.idTokenClaims.given_name

Web アプリを仕上げる

  1. コード エディターで app.js ファイル開き、app.js からコードを追加します。

  2. コード エディターで server.js ファイル開き、server.js からコードを追加します。

  3. コード エディターで package.json ファイルを開き、scripts プロパティを次のように更新します。

    "scripts": {
    "start": "node server.js"
    }
    

Web アプリを実行してテストする

  1. ターミナルで、ciam-sign-in-node-express-web-app などの Web アプリを含むプロジェクト フォルダーに移動します。

  2. ご利用のターミナルで、次のコマンドを実行します。

    npm start
    
  3. ブラウザーを開き、http://localhost:3000 に移動します。 以下のスクリーンショットのようなページが表示されます。

    ノード Web アプリへのサインインのスクリーンショット。

  4. ページの読み込みが完了したら、[サインイン] リンクを選択します。 サインインするように求められます。

  5. サインイン ページで、[メール アドレス] を入力して [次へ] を選択し、[パスワード] を入力してから [サインイン] を選択します。 アカウントをお持ちでない場合は、[アカウントをお持ちではない場合、作成できます] リンクを選択します。これで、サインアップ フローが開始されます。

  6. サインアップ オプションを選択した場合は、メール、ワンタイム パスコード、新しいパスワード、その他のアカウントの詳細を入力すると、サインアップ フロー全体が完了します。 以下のスクリーンショットのようなページが表示されます。 サインイン オプションを選択すると、同様のページが表示されます。

    ID トークン要求の表示のスクリーンショット。

  7. [サインアウト] を選択して Web アプリからユーザーをサインアウトするか、ID トークン要求を表示する を選択して すべての ID トークン要求を表示します。

関連項目