diff --git a/dictation_client/src/pages/LoginPage/index.tsx b/dictation_client/src/pages/LoginPage/index.tsx index 58d6796..61e66d1 100644 --- a/dictation_client/src/pages/LoginPage/index.tsx +++ b/dictation_client/src/pages/LoginPage/index.tsx @@ -1,4 +1,5 @@ import { useMsal } from "@azure/msal-react"; +import { AuthError } from "@azure/msal-browser"; import { AppDispatch } from "app/store"; import { isIdToken } from "common/token"; import Footer from "components/footer"; @@ -11,10 +12,7 @@ import { useDispatch, useSelector } from "react-redux"; import { useNavigate } from "react-router-dom"; const LoginPage: React.FC = (): JSX.Element => { - /* XXX B2CのログインからIDトークンの取得までの挙動を整理する必要がある。 - 「プロダクト バックログ項目 1655: ログイン周りの挙動について調査・整理する」で調査・整理する。 - */ - const { accounts, instance } = useMsal(); + const { instance } = useMsal(); const dispatch: AppDispatch = useDispatch(); const navigate = useNavigate(); const [, i18n] = useTranslation(); @@ -34,7 +32,7 @@ const LoginPage: React.FC = (): JSX.Element => { if (meta.requestStatus === "fulfilled") { const accessToken = loadAccessToken(); const refreshToken = loadRefreshToken(); - /* TODO デスクトップアプリが無いためメモ帳を開くようにしている + /* TODO 1899:デスクトップアプリが無いためメモ帳を開くようにしている デスクトップアプリチームでスキーム名が決まり次第修正する */ const url = `note:login?accessToken=${accessToken}&refreshToken=${refreshToken}&language=${i18n.language}`; // カスタムURLスキーム @@ -51,18 +49,24 @@ const LoginPage: React.FC = (): JSX.Element => { // TODO 将来的にトークンの取得処理をoperations.ts側に移動させたい。useEffect内で非同期処理を行いたくない。 useEffect(() => { + if (status !== "none") { + // ログイン処理で、何回か本画面が描画される契機があるが、認証処理は一度だけ実施すればよいため認証処理実行済みであれば何もしない + return; + } + (async () => { - if (accounts.length >= 1) { - const { homeAccountId, idTokenClaims } = accounts[0]; - if (idTokenClaims) { - if (idTokenClaims.aud) { + try { + const loginResult = await instance.handleRedirectPromise(); + if (loginResult && loginResult.account) { + const { homeAccountId, idTokenClaims } = loginResult.account; + if (idTokenClaims && idTokenClaims.aud) { // IDトークンの取得 const idTokenString = localStorage.getItem( `${homeAccountId}-${ import.meta.env.VITE_B2C_KNOWNAUTHORITIES }-idtoken-${idTokenClaims.aud}----` ); - if (idTokenString && status === "none") { + if (idTokenString) { const idTokenObject = JSON.parse(idTokenString); if (isIdToken(idTokenObject)) { await login(idTokenObject.secret); @@ -70,9 +74,20 @@ const LoginPage: React.FC = (): JSX.Element => { } } } + } catch (e) { + // AAD B2Cの多要素認証画面やパスワードリセット画面で「cancel」をクリックすると、handleRedirectPromise()にてエラーが発生するため、 + // それをハンドリングして適切な画面遷移処理を行う。 + if (e instanceof AuthError) { + // エラーコードはerrorMessageの中の一部として埋め込まれており完全一致で取得するのは筋が悪いため、部分一致で取得する。 + // TODO 他にもAADB2Cのエラーコードを使用する箇所が出てきた場合、定数化すること + if (e.errorMessage.startsWith("AADB2C90091")) { + navigate("/"); + } + } } })(); - }, [accounts, login, status]); + }, [instance, login, navigate, status]); + return ( <>