LoginSignup
5
0

msal-reactでAzure AD認証を実現する

Last updated at Posted at 2023-07-07

はじめに

ReactでAzure ADを使用したログイン認証や、Graph APIとの連携を実現したいことがあると思います。
自前で実装するのか・・・と落胆する必要はなく、Microsoftがmsal-reactといったライブラリを提供しています!msal-reactを使用することでAzure AD認証を簡単に自前のアプリに組み込むことができ、Graph APIとの連携も容易となるので紹介させてください!

事前準備

Reactアプリ作成

今回もviteを使ってReactアプリを作成します。

実行コマンド
npm create vite@latest

作成後はAzure AD認証を実現する@azure/msal-browser,@azure/msal-reactとHTTPライブラリaxiosを入れておきます。

実行コマンド
npm install @azure/msal-browser @azure/msal-react axios

インストールしたら動作確認しておきましょう。

実行コマンド
npm run dev

動作確認

スクリーンショット 2023-06-17 11.06.13.png
この画面が表示されていればOKです!

Azure AD ギャラリーに独自のアプリケーションを追加

Azure AD ギャラリーに独自のアプリケーションを追加します。
独自アプリケーションを事前に登録することで、Azure AD認証を組み込むことを可能とします。

下記画面から独自のアプリケーションの作成を選択します。04f598e0-861e-6afc-be4f-a9b50b49054a.png
名前は任意のものを入れていただいて構いません。今回はReactAuthTestとしています。
開発中アプリのため、アプリケーションを登録してAzure ADと統合しますを選択します。

6fb44b14-14ac-a56e-7776-0be103a4bad9.png

Azure ADに登録されているユーザーのみ認証したいためこの組織ディレクトリのみに含まれるアカウントを選択します。
リダイレクトURIはviteでデバッグするときのURI:http://localhost:5173/を指定し、アプリケーションの種別はシングルページアプリケーションを指定します。

02063cc7-5772-00f9-1538-e4a25dcc77cb.png

赤枠部分の説明にも記載があるようにアプリケーションはシングルページアーキテクチャであり、承認コードフローを使用しないので、アクセストークンIDトークンのチェックボックスを有効にします。

8c4e595b-236a-d8ab-97a5-1c22ea2b2c37.png

これで準備は完了です!

下記2点はReactアプリケーションで使用する情報なのでメモしておきましょう。

  • アプリケーション(クライアント)ID
    Azure AD ギャラリーに追加したアプリの概要ブレードを開き、赤枠部分のアプリケーション(クライアント)IDの値
    7bf3e66d-a97a-6edf-e2c0-8f3260851de0.png
  • プライマリ ドメイン
    Azure Active Directoryの概要ブレードを開き、赤枠部分のプライマリ ドメインの値
    bf42c094-fded-3234-16e6-d8947a1cc166.png

実装(Azure AD認証)

先ほどメモした情報を.envに環境変数として記載します。
viteでReactプロジェクトを作成した場合は、キー名のプレフィックスにVITEとつけることで環境変数として使用可能です。

  • VITE_CLIENT_IDはメモしたアプリケーション(クライアント)IDの値
  • VITE_AUTHORITYはメモしたプライマリ ドメインの値
  • VITE_REDIRECT_URIはリダイレクトURIで指定したURI
.env
VITE_CLIENT_ID = "メモしたアプリケーション(クライアント)IDの値"
VITE_AUTHORITY = "メモしたプライマリ ドメインの値"
VITE_REDIRECT_URI = "http://localhost:5173/"

まずはmain.jsxに処理を追記します。
認証を行うインスタンスを作成し、MsalProviderを使用してそれぞれのコンポーネントが認証を実行できるようにします。
接続情報は.envから取得し、認証に成功した場合のアクセストークン保存先はsessionStorageを指定します。

main.jsx
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";

+ //インポートを追加
+ import { PublicClientApplication } from "@azure/msal-browser";
+ import { MsalProvider } from "@azure/msal-react";

+ //msalInstanceを作成
+ const msalInstance = new PublicClientApplication({
+   auth: {
+     //環境変数から認証情報を取得
+     //アプリケーション(クライアント)ID
+     clientId: import.meta.env.VITE_CLIENT_ID,
+     //プライマリ ドメイン
+     authority: `https://login.microsoftonline.com/${
+       import.meta.env.VITE_AUTHORITY
+     }`,
+     //リダイレクトURI
+     redirectUri: import.meta.env.VITE_REDIRECT_URI,
+   },
+   //キャッシュ先
+   cache: {
+     //セッションストレージ
+     cacheLocation: "sessionStorage",
+   },
+ });

const root = ReactDOM.createRoot(document.getElementById("root"));

root.render(
  <React.StrictMode>
+     <MsalProvider instance={msalInstance}>
      <App />
+     </MsalProvider>
  </React.StrictMode>
);

次にApp.jsxに機能を追加します。先にライブラリから必要なコンポーネントやHooksをインポートしておきます。

App.jsx
+ import React, { useState } from "react";
+ import {
+   AuthenticatedTemplate,
+   UnauthenticatedTemplate,
+   useMsal,
+ } from "@azure/msal-react";

Azure AD認証を実行するログインボタンを作成していきます。
引数でGraph APIで要求する権限を指定する必要があるため、今回はユーザー情報を取得する権限User.Readを要求します。

要件に応じて使用したい権限は変わってくると思うので、詳しくは公式ドキュメントを参考にしていただければと思います。

ログインボタンを押下したらProviderから受け取ったインスタンスに提供されているメソッドloginRedirectを実行して、Azure AD認証の画面へリダイレクトさせます。

App.jsx
+ //Azure AD認証でGraph APIに要求する権限
+ const loginRequest = {
+   //ユーザーを取得する権限
+   scopes: ["User.Read"]
+ };

+ /**
+  * ログインボタンを押下したらAzure ADの認証画面へリダイレクトさせる
+  * @returns ログインボタンコンポーネント
+  */
+ const LoginButton = () => {
+   //ProviderからAD認証用のインスタンスを取得
+   const { instance } = useMsal();
+   //ログインボタン実行時の関数
+   const handleLogin = () => {
+     //AD認証実現画面へリダイレクト。引数にGraph APIに要求する権限を設定
+     instance.loginRedirect(loginRequest);
+   };

+   return (
+     <>
+       <button onClick={() => handleLogin()}>ログイン</button>
+     </>
+   );
+ };

export default function App() {
  return (
    <div className="App">
+       {/*ログイン成功時に表示*/}
+       <AuthenticatedTemplate>
+         <div>ログインに成功しました!</div>
+       </AuthenticatedTemplate>
			
+       {/*未ログイン時に表示*/}
+       <UnauthenticatedTemplate>
+         <div>ログインしてください</div>
+         <LoginButton />
+       </UnauthenticatedTemplate>
    </div>
  );
}

AuthenticatedTemplateタグ内のコンポーネントはログイン後に表示されて、UnauthenticatedTemplateタグ内のコンポーネントは未ログイン状態の時に表示されます。
未ログイン状態ではログインボタンを表示したいのでUnauthenticatedTemplateタグ内に配置します。

Azure AD認証の実装は完了したので動作確認します!

動作確認

初期表示

スクリーンショット 2023-06-17 22.57.13.png

ログインボタン押下後

Microsoftが提供するAzure AD認証のログイン画面が表示されました!

スクリーンショット 2023-06-17 22.59.38.png

ログイン完了後

ログイン後はリダイレクトURIに指定したhttp://localhost:5173/にリダイレクトされていますね。またログインに成功したため、AuthenticatedTemplate内の文言が表示されています!

スクリーンショット 2023-06-17 23.00.49.png

Session Storage

Session Storageを確認すると、取得したIdTokenなど保存されていますね!

b1971585-29d1-f585-fae4-a3a3e39073be.png

次はログインした状態でGraph APIと連携できるよう実装を進めていきます。

実装(Graph APIと連携)

アクセストークンを引数で受け取り、Graph APIを使用してユーザー情報を取得する関数を作成します。

App.jsx
+ /**
+  * Graph APIをコールしユーザー情報を取得する
+  * @param {Object} accessToken 
+  * @returns Graph APIで取得したユーザー情報
+  */
+ const callGraphApi = async (accessToken) => {
+   //受け取ったアクセストークンをヘッダーに設定してGraph APIをコール
+   const response = await axios.get("https://graph.microsoft.com/v1.0/me", {
+     headers: {
+       Authorization: `Bearer ${accessToken}`,
+     },
+   });
+   return response.data;
+ };

今回はユーザー情報を取得するエンドポイントGET /meを使用していますが、メールを作成したいなど要件に応じて使用するエンドポイントは変わってきますので、こちらも公式ドキュメントを参照していただければと思います。

アクセストークンを取得してGraph APIを実行し、取得したユーザー情報を表示するコンポーネントを作成します。

App.jsx
//Azure AD認証でGraph APIに要求する権限
const loginRequest = {
  //ユーザーを取得する権限
  scopes: ["User.Read"]
};

+ /**
+  * Graph APIをコールし、取得したユーザー情報を表示するコンポーネント
+  * @returns ユーザー情報表示コンポーネント
+  */
+ const ProfileContent = () => {
+   //accountsはログイン時に取得したユーザー情報
+   const { instance, accounts } = useMsal();
+   //Graph APIで取得するデータのState
+   const [graphData, setGraphData] = useState(null);
+ 
+   function RequestProfileData() {
+     //★accuireTokenSilentを使用してアクセストークンを取得する。
+     instance
+       .acquireTokenSilent({
+         ...loginRequest, //Graph APIに要求する権限
+         account: accounts[0],//ログインユーザー情報
+       })
+       //取得に成功したらアクセストークンをGraph API実行関数に渡して実行
+       .then((response) => {
+         callGraphApi(response.accessToken).then((data) => {
+           //Graph APIのデータをStateに保存
+           setGraphData(data);
+           console.log(data);
+         });
+       });
+   }

+   return (
+     <>
+       <h5 className="">Welcome {accounts[0].name}</h5>
+       <br />
+      {/*Graph APIのデータがStateに保存されている場合*/}
+       {graphData ? (
+         <div>
+           <div>id:{graphData.id}</div>
+           <div>名前:{graphData.displayName}</div>
+         </div>
+       ) : (
+         {/*Graph APIのデータがStateに保存されていない場合*/}
+         <button variant="secondary" onClick={RequestProfileData}>
+           Graph API実行
+         </button>
+       )}
+     </>
+   );
+ };

★マークの処理について説明すると下記流れになります。

  1. acquireTokenSilentメソッドでAzure AD認証で取得したユーザー情報とGraph APIに要求する権限を引数に設定してアクセストークンを取得する。
  2. アクセストークンをcallGraphApiの引数に設定して、ユーザー情報を取得する。
  3. ユーザー情報をStateに保持し、画面に表示する。

最後に作成したコンポーネントをログイン時に表示するようにします。

App.jsx
export default function App() {
  return (
    <div className="App">
      {/*ログイン成功時に表示*/}
      <AuthenticatedTemplate>
-        <div>ログインに成功しました!</div>
+        <ProfileContent />
      </AuthenticatedTemplate>

      {/*未ログイン時に表示*/}
      <UnauthenticatedTemplate>
        <div>ログインしてください</div>
        <LoginButton />
      </UnauthenticatedTemplate>
    </div>
  );
}

実装完了です!動作確認していきます。

動作確認

ログイン後画面

ログイン後に表示される画面です。ここでGraph API実行ボタンを押下します。
スクリーンショット 2023-06-24 10.04.59.png

Graph API実行ボタンを押下後

0eb81154-0b44-3d16-ab80-aa6ab81144a7.png

Graph APIで取得した情報が無事表示されましたね!

おわりに

msal-reactはいかがでしたでしょうか?Azure AD認証が簡単に実現できたと思います!
また、ログイン後のアクセストークン取得やGraph APIとの連携も簡単です。
ReactでAzure AD認証を使用する場合はぜひ使ってみてください!

5
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
0