Azure AD B2CをReact(SPA)でログインする方法についてまとめました。初期では1パターンしか知らなかったため、紆余曲折ありましたが使い分けができる程度には成長しました。使ったことがある人はさっくりと、知らなかった人はこっそりと勉強していってください。新米フロントエンドエンジニアの技術ログ
ご挨拶
どもども!燃え尽き症候群は深刻な問題だなと痛感している龍ちゃんです。ここ数日で一気に涼しくなりましたね。これぐらいの気温で固定してもらえると電気代も抑えられて、我が家の財政にも優しいのですが…..在宅ワークだと電気代が高騰するのが悩みです。
さて、今回は、React(SPA)を用いた「Azure AD B2C」でのログインの方法についてまとめる回になります。お手軽?に認証基盤を導入することができるという点とAzureのサービスの親和性を考えて、「Azure AD B2C」という選択肢を取ることが良くあります。ログインを実装する方法に関しては、3パターンあるのでその方法について解説していきます。
ブログで取り扱う内容としては以下になります。
- React(SPA)でAzure AD B2Cでのログインに関する共通部分
useMsal
を用いた自力実装useMsalAuthentication
を用いた半自動実装MsalAuthenticationTemplate
を用いた自動実装
3パターンもあると、どれを使うべきか悩ましいところです。すべての実装をリダイレクト形式で処理をするように作成しています。
それでは実装の解説に入っていきます。
実装
まず、どの実装パターンでも必要な共通実装部分について作成していきます。その後、各実装について解説をしていきます。
React(SPA)でAzure AD B2Cを扱うための共通実装
【Msal.js】を利用するにあたって、絶対作成しなければならないコードが以下になります。接続先を示すファイルを設定ファイルとして切り出しています。ここの設定ファイルに関しては、以下のブログで解説しています。公式のガイドもわかりやすいのでおいておきます。
PublicClientApplication
を構築するため以外の設定ファイルが含まれています。
import { Configuration } from '@azure/msal-browser';
const AzureClientId: string = import.meta.env.VITE_AZURE_CLIENT_ID || '';
const AzureScopes: string[] = [import.meta.env.VITE_AZURE_SCOPE || ''];
const AzureAuthority: string = import.meta.env.VITE_AZURE_AUTHORITY || '';
const AzureKnownAuthorities: string[] = [import.meta.env.VITE_AZURE_KNOWN_AUTHORITY || ''];
export const msalConfig: Configuration = {
auth: {
clientId: AzureClientId,
authority: AzureAuthority,
knownAuthorities: AzureKnownAuthorities,
redirectUri: window.location.origin,
},
cache: {
cacheLocation: 'sessionStorage',
storeAuthStateInCookie: false,
},
};
以下のコードが【Msal.js】をReactで使用するためには必要なコンポーネントになります。
import { PublicClientApplication } from '@azure/msal-browser';
import { MsalProvider } from '@azure/msal-react';
import { msalConfig } from '@/constants/authAzure';
export const AzureConfigComponent = (props: { children: React.ReactNode }) => {
const { children } = props;
const pca = new PublicClientApplication(msalConfig);
return (
<MsalProvider instance={pca}>
{children}
</MsalProvider>
);
};
MsalProvider
以下ではないと、【Msal.js】が提供している機能が動かないのでご注意ください。
useMsalを用いた自力実装
公式のGitの資料としては以下になります。こちらは、ログインの判定からログインの処理までをすべて自力で実装する内容になります。こちらの実装方法を採用する場面としては、トップページの一部が、ログイン状態によって変化するページに適しています。
import { useCallback } from 'react';
import { useMsal } from '@azure/msal-react';
export const useAzureAuth = () => {
const { instance } = useMsal();
const loginAzure = useCallback(async () => {
instance.loginRedirect();
}, [instance]);
const logoutAzure = useCallback(async () => {
instance.logout();
}, [instance]);
return {
logoutAzure,
loginAzure,
};
};
上記のHooksに示した方法が、Redirect方式でログインをする場合の対応になります。ボタンコンポーネントと複合して使用することで、ログイン処理やログアウト処理を実装することができます。
以下使用方法のサンプルになります。
import { AuthenticatedTemplate, UnauthenticatedTemplate } from '@azure/msal-react';
import { useAzureAuth } from '@/hooks/useAzureAuth';
export const TestPage = () => {
const { loginAzure, logoutAzure } = useAzureAuth();
return (
<>
<UnauthenticatedTemplate>
ログイン前に表示されるページ<button onClick={loginAzure}>ログイン</button>
</UnauthenticatedTemplate>
<AuthenticatedTemplate>
ログイン後に表示されるページ <button onClick={logoutAzure}>ログアウト</button>
</AuthenticatedTemplate>
</>
);
};
UnauthenticatedTemplate
とAuthenticatedTemplate
は【msal-react】が提供しているコンポーネントになります。ログイン状態によって一部分のUIを変化させたい場合は、非常に活躍します。
useMsalAuthenticationを用いた半自動実装
公式のGitの資料としてはこちらになります。こちらは、呼び出したタイミングで自動でログイン処理が走ります。エラーが出た場合は、ReactのuseEffect
と併用することでログインの処理を実装することができます。以下がコードになります。
import { useEffect } from 'react';
import { InteractionRequiredAuthError, InteractionType } from '@azure/msal-browser';
import { useMsalAuthentication } from '@azure/msal-react';
export const TestPage = () => {
const { login, result, error } = useMsalAuthentication(InteractionType.Redirect);
useEffect(() => {
if (error instanceof InteractionRequiredAuthError) {
login(InteractionType.Redirect);
} else {
console.log(result);
}
}, [error, login, result]);
return <>ログイン完了</>;
};
useMsalAuthentication
では、ログインの機能とログイン結果を取得することができます。result
はログインの結果が格納されているため、アクセストークンの取得を担保することができます。
こちらを使用する場合では、「アクセス~ログイン処理」を実行するまで、画面がちらつくため自前でローディングの機能を実装する必要があります。ちらつきの原因としては、【Msal.js】の起動時にReactのコンポーネント再レンダリングが発生することが考えられます。そのため、判定ロジック前に
こちらの解消方法としては、useMsal
で取得することができるinProgress
を使用します。inProgress
は【Msal.js】の状態を返答してくれる変数になります。こちらの値は【InteractionStatus】で定義されており、この値がNoneになった時にログイン判定までが終了したことになります。
import { useEffect, useMemo } from 'react';
import { InteractionRequiredAuthError, InteractionStatus, InteractionType } from '@azure/msal-browser';
import { useMsal, useMsalAuthentication } from '@azure/msal-react';
import { LoadingComponent } from '@/pages/LoadingPage';
export const TestPage = () => {
const { inProgress } = useMsal();
const { login, result, error } = useMsalAuthentication(InteractionType.Redirect);
useEffect(() => {
if (error instanceof InteractionRequiredAuthError) {
login(InteractionType.Redirect);
}
}, [error, login]);
const userID = useMemo(() => {
if (!result || !result.account.idTokenClaims?.oid) return '';
return result.account.idTokenClaims.oid;
}, [result]);
if (inProgress != InteractionStatus.None) return <LoadingComponent />;
return <>ログイン完了{userID}</>;
}
MsalAuthenticationTemplateを用いた自動実装
公式のGitの資料としてはこちらになります。こちらは、前述の方法と異なりコンポーネントとして提供されています。ログイン状態でなければ自動でログイン処理を行い、ログイン中や起動判定なども自動で行ってくれます。
import { InteractionType } from '@azure/msal-browser';
import { MsalAuthenticationResult, MsalAuthenticationTemplate } from '@azure/msal-react';
import { LoadingComponent } from '@/pages/LoadingPage';
export const TestPage = () => {
const ErrorComponent = (result: MsalAuthenticationResult) => {
const { error } = result;
return <>{error}</>;
};
return (
<>
<MsalAuthenticationTemplate
interactionType={InteractionType.Redirect}
authenticationRequest={{}}
errorComponent={ErrorComponent}
loadingComponent={LoadingComponent}
>
ログイン完了
</MsalAuthenticationTemplate>
</>
);
};
使用方法としては、上記になります。こちらは、コンポーネントにPropとしてerrorComponent
とloadingComponent
を渡すことが求められます。名前の通り処理中とエラーが表示された際に、コンポーネントの差し替えを自動で行ってくれます。
単純にコンポーネントレベルで実現したい場合は、楽に実装することができるので非常に便利だと思います。
3パターンのログイン処理の比較
3パターンの実装について紹介したので、それぞれの比較を行ってい置きたいと思います。自動でログイン処理を行いたい場合は、useMsalAuthentication
かMsalAuthenticationTemplate
になるかと思います。
自動ログインを実装したい場合は、useMsalAuthentication
とMsalAuthenticationTemplate
を使用することがベターだと思います。ログイン後でページの一部分のみが変わる場合は、useMsal
とUnauthenticatedTemplate
・AuthenticatedTemplate
を併用することが良い選択しただと思います。どの手法でもログイン情報を取得することができるので、要件によって構築方法が変化するかと思います。
個人的な好みとしては、MsalAuthenticationTemplate
がコード量が少なくてよいかと思います。エラーハンドリングがブラックボックス化される部分は否めないですが、React側でキャッチすることで拾えることができるかと思います。一方で、useMsalAuthentication
でログイン処理のちらつきを抑制することができるのであれば、トークン取得もセットでできるのでお得です。
終わりに
お疲れ様です。Azure AD B2Cはお手軽にログイン機能を実装することができるので、非常に便利です。ログイン機能があるだけで、自主開発であればレベルがぐっと上がる気がします。商用のサービスであれば、認証・認可などはがっつり必要となる機能だと思います。
去年一年は、何もわからないからAzureのサービス「チョットツカエル」になったと思います。昔書いたブログのミスも見つけたので、反省しながら修正しておきます。
フロントエンドの記事をひと段落させたら、フロントとバック(+デザイン)の記事を書いていきたいと思っています。年内に出したいものですね。
ではまた~