yarn
を用いますが、npm
でももちろんできますので、必要に応じて読み替えていただけると助かります。# プロジェクト nextjs-aadb2c の作成(TypeScript) yarn create next-app --typescript nextjs-aadb2c
cd nextjs-aadb2c yarn dev
pages
がルートにありますが、この後の編集では lib
なども作っていきたいので、src
ディレクトリを作成します。src
の中に pages
, styles
を格納し、lib
ディレクトリもその中に作っておくと良いでしょう。// src/pages/index.tsx import type { NextPage } from 'next'; const Home: NextPage = () => { return <h1>React & Next.js と AADB2C の連携</h1>; }; export default Home;
# msal-react のインストール yarn add @azure/msal-react @azure/msal-browser
authority
で登場する kikagakuapps
は私が AADB2C で登録した名前です。b2c_1_signin
はユーザーフローで作成した名前でしたね。これらを合わせて設定してみましょう。詳細な情報に困ったときは、以下のようにユーザーフローで定義されているページを見に行くと、情報のヒントがあるはずです。// src/lib/auth/config.ts import { Configuration } from '@azure/msal-browser'; export const msalConfig: Configuration = { auth: { clientId: '34d76626-.............', authority: 'https://kikagakuapps.b2clogin.com/kikagakuapps.onmicrosoft.com/b2c_1_signin', knownAuthorities: ['kikagakuapps.b2clogin.com'], redirectUri: '/', postLogoutRedirectUri: '/', }, cache: { cacheLocation: 'localStorage', }, }; export const loginRequest = { scopes: ['openid', 'offline_access'], };
cacheLocation
を localStorage
に設定しています。デフォルトでは sessionStorage
です。違いはブラウザを閉じたときに記憶している (localStorage) か否 (sessionStorage) かだと考えるとわかりやすいと思います。セキュリティ的には、情報を短く持つ sessionStorage
が推奨されています。この辺りは、ユーザー体験とバランスを取ると良いでしょう。MsalProvide
を追加しましょう。// src/pages/_app.tsx import { PublicClientApplication } from '@azure/msal-browser'; import { MsalProvider } from '@azure/msal-react'; import { msalConfig } from '../lib/auth/config'; import '../styles/globals.css'; import type { AppProps } from 'next/app'; function MyApp({ Component, pageProps }: AppProps) { const pca = new PublicClientApplication(msalConfig); return ( <MsalProvider instance={pca}> <Component {...pageProps} /> </MsalProvider> ); } export default MyApp;
// src/components/SigninBtn.tsx import { useMsal } from '@azure/msal-react'; import { loginRequest } from '../lib/auth/config'; export default function SigninBtn(): JSX.Element { const { instance } = useMsal(); return ( <div> <button onClick={() => instance.loginRedirect(loginRequest)}>ログイン</button> </div> ); }
// src/pages/index.tsx import type { NextPage } from 'next'; import SigninBtn from '../components/SigninBtn'; const Home: NextPage = () => { return ( <> <h1>React & Next.js と AADB2C の連携</h1> <SigninBtn /> </> ); }; export default Home;
useCurrentUser
という Hook を作っておくと、色々なページから利用できて便利です。// src/hooks/useCurrentUser.ts import { AccountInfo } from '@azure/msal-browser'; import { useMsal } from '@azure/msal-react'; interface Account extends AccountInfo { idTokenClaims: { aud: string; auth_time: number; family_name: string; given_name: string; emails: string[]; iss: string; nbf: number; nonce: string; sub: string; tfp: string; ver: string; }; } export interface User { sub: string; familyName: string; givenName: string; email: string; } const useCurrentUser = (): User | null | undefined => { const { accounts } = useMsal(); if (accounts.length > 0) { const account = accounts[0] as Account; const user: User = { sub: account.idTokenClaims?.sub, familyName: account.idTokenClaims?.family_name, givenName: account.idTokenClaims?.given_name, email: account.idTokenClaims?.emails[0], }; return user; } return null; }; export default useCurrentUser;
useCurrentUser
を利用して、まずはターミナルで取得したユーザー情報を表示してみましょう。// src/pages/index.tsx import type { NextPage } from 'next'; import SigninBtn from '../components/SigninBtn'; import useCurrentUser from '../hooks/useCurrentUser'; const Home: NextPage = () => { const user = useCurrentUser(); console.log(user); return ( <> <h1>React & Next.js と AADB2C の連携</h1> <SigninBtn /> </> ); }; export default Home;
AuthenticatedTemplate
のブロック内に、非ログイン時の情報は UnauthenticatedTemplate
に記載するだけと超簡単です。// src/pages/index.tsx import type { NextPage } from 'next'; import { AuthenticatedTemplate, UnauthenticatedTemplate } from '@azure/msal-react'; import SigninBtn from '../components/SigninBtn'; import useCurrentUser from '../hooks/useCurrentUser'; const Home: NextPage = () => { const user = useCurrentUser(); return ( <> <h1>React & Next.js と AADB2C の連携</h1> <UnauthenticatedTemplate> <SigninBtn /> </UnauthenticatedTemplate> <AuthenticatedTemplate> <p> こんにちは、{user?.familyName} {user?.givenName} さん </p> <p>メールアドレス:{user?.email}</p> </AuthenticatedTemplate> </> ); }; export default Home;
// src/components/SignoutBtn.tsx import { useMsal } from '@azure/msal-react'; export default function SigninBtn(): JSX.Element { const { instance } = useMsal(); return ( <div> <button onClick={() => instance.logout()}>ログアウト</button> </div> ); }
// src/pages/index.tsx import type { NextPage } from 'next'; import { AuthenticatedTemplate, UnauthenticatedTemplate } from '@azure/msal-react'; import SigninBtn from '../components/SigninBtn'; import SignoutBtn from '../components/SignoutBtn'; import useCurrentUser from '../hooks/useCurrentUser'; const Home: NextPage = () => { const user = useCurrentUser(); return ( <> <h1>React & Next.js と AADB2C の連携</h1> <UnauthenticatedTemplate> <SigninBtn /> </UnauthenticatedTemplate> <AuthenticatedTemplate> <p> こんにちは、{user?.familyName} {user?.givenName} さん </p> <p>メールアドレス:{user?.email}</p> <SignoutBtn /> </AuthenticatedTemplate> </> ); }; export default Home;
UnauthenticatedTemplate
のブロック内で書かれたログインボタンのみが表示されると成功です。新着記事
関連記事
著者