はじめに
Next.jsでログイン処理時にログインAPIを呼び出し、レスポンスのログイン情報をlocalStorage
に保持するような処理を実装しました。
しかし、このままではログアウトをしない限り、ほぼ永続的にデータが保持されてしまいます。
そこでlocalStorage
に保持したログイン情報に有効期限を設定し、期限切れの場合はログイン画面へリダイレクトする処理を実装しました。
前提
Next.jsプロジェクトを作成済み
ログインAPIをバックエンドで実装済み
axios
インストール済み
環境
- React 17.0.1
- Next.js 10.2.3
- lscache 1.3.0
- tailwindcss 2.2.0
実装の流れ
1.プロジェクトにlscache
をインストール
2.ログイン画面の実装
3.ログイン用のフックを作成
4.ホーム画面とAboutページの実装
5._app.jsx
の修正
1.プロジェクトにlscache
をインストール
$ yarn add lscache
2.ログイン画面の実装
Next.jsのファイルシステムルーティングの通り、下記パスにlogin.jsx
ファイルを作成。
ログイン画面を実装します。
import Head from "next/head";
import { useState } from "react";
import { useAuth } from "src/hooks/useAuth";
const Login = () => {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const { login } = useAuth();
const onChangeEmail = (e) => {
setEmail(e.target.value);
};
const onChangePassword = (e) => {
setPassword(e.target.value);
};
const onClickLogin = () => {
login(email, password);
};
return (
<div className='bg-gray-500 flex flex-col items-center justify-center min-h-screen py-2'>
<Head>
<title>ログイン画面</title>
<link rel='icon' href='/favicon.ico' />
</Head>
<main className='flex flex-col items-center justify-center w-full flex-1 px-20 text-center'>
<div className='container mx-auto h-full flex flex-1 justify-center items-center'>
<div className='w-full max-w-md'>
<div className='leading-loose'>
<div className='max-w-md m-4 p-10 bg-white bg-opacity-25 rounded shadow-xl'>
<input
className='w-full px-5 py-1 text-gray-700 bg-gray-300 rounded focus:outline-none focus:bg-white'
type='email'
placeholder='メールアドレス'
required
value={email}
onChange={onChangeEmail}
/>
<div className='mt-2'>
<input
className='w-full px-5 py-1 text-gray-700 bg-gray-300 rounded focus:outline-none focus:bg-white'
type='password'
placeholder='パスワード'
required
value={password}
onChange={onChangePassword}
/>
</div>
<div className='mt-4 items-center flex justify-between'>
<button
className='px-4 py-1 text-white font-light tracking-wider bg-gray-900 hover:bg-gray-800 rounded'
onClick={onClickLogin}
>
ログイン
</button>
</div>
</div>
</div>
</div>
</div>
</main>
</div>
);
};
export default Login;
ログインボタンを押下時に後述のログイン用のフックを呼び出して、ログイン処理をしています。
3.ログイン用のフックを作成
axios
でログインAPIを呼び出し、ログイン処理を行うフックを下記の通り実装します。
ここでlocalStorage
に期限付きでログイン情報を保持します。
import axios from "axios";
import { useRouter } from "next/router";
import lscache from "lscache";
export const useAuth = () => {
const router = useRouter();
const login = (email, password) => {
axios
// ご自身のログインAPIのURLを設定
.post(`http://localhost:3001/auth/sign_in`, {
email: email,
password: password,
})
.then((res) => {
if (res.data) {
// ポイント① lscacheを用いてlocalStorageに期限付きでログインIDを保持
lscache.set("loginId", JSON.stringify(resData.id), 1);
router.push("/");
} else {
console.log("error");
}
})
.catch(() => {
console.log("catch");
})
.finally(() => {
console.log("finally");
});
};
return { login };
};
ポイント①箇所で期限設定とログイン情報の保持を行い、ホーム画面へ遷移させています。
第1引数、第2引数でレスポンスデータのIDをloginId
に保存し、第3引数で有効期限を設定しています。
上記のように「1」と設定すると1分間の有効期限が設定されます。
4.ホーム画面とAboutページの実装
動作確認しやすいように相互に行き来できるリンクを含めて実装します。
import Head from "next/head";
import Link from "next/link";
const Home = () => {
return (
<div>
<Head>
<title>ホーム</title>
<link rel='icon' href='/favicon.ico' />
</Head>
<div className='content'>
<div className='flex items-center justify-between w-full my-4 pl-4 sm:pr-4'>
<div className='mr-6'>
<h2 className='text-3xl md:text-4xl font-semibold tracking-tight leading-7 md:leading-10 mb-1 truncate'>
ホーム画面
</h2>
<div className='text-teal-600 '>
<Link href='/about'>
<a>Aboutページへ</a>
</Link>
</div>
</div>
</div>
</div>
</div>
);
};
export default Home;
import Head from "next/head";
import Link from "next/link";
const About = () => {
return (
<div>
<Head>
<title>About</title>
<link rel='icon' href='/favicon.ico' />
</Head>
<div className='content'>
<div className='flex items-center justify-between w-full my-4 pl-4 sm:pr-4'>
<div className='mr-6'>
<h2 className='text-3xl md:text-4xl font-semibold tracking-tight leading-7 md:leading-10 mb-1 truncate'>
Aboutページ
</h2>
<div className='text-teal-600 '>
<Link href='/'>
<a>HOMEへ</a>
</Link>
</div>
</div>
</div>
</div>
</div>
);
};
export default About;
5._app.jsx
の修正
_app.jsx
ではログイン時に保持したloginId
の有効期限が切れていた場合に削除処理を行い、ログイン画面へリダイレクトする処理を実装しています。
useEffect
を用いて、画面遷移や画面リロードの際に上記の処理が動作するように実装しています。
import "tailwindcss/tailwind.css";
import { useEffect } from "react";
import lscache from "lscache";
const MyApp = ({ Component, pageProps, router }) => {
// ポイント② useEffectを使用
useEffect(() => {
// ポイント③ ログインページへのアクセスの場合は処理をしない
if (router.pathname === "/login") return;
// ポイント④ 期限切れのデータを削除
lscache.flushExpired();
// ポイント⑤ loginIdが取得できない場合、ログインページへリダイレクト
if (!lscache.get("loginId")) {
router.push("/login");
}
}, [Component]);
return (
<>
<Component {...pageProps} />
</>
);
};
export default MyApp;
ポイント②でuseEffect
の第2引数にComponent
を設定して、画面遷移や画面リロードなどの際に処理が走るようにしています。
ポイント③でログインページへのアクセスの際は処理を行わないようにしています。
ポイント④で有効期限の切れたストレージのデータを削除しています。
ポイント⑤loginId
のデータが取得できなかった場合、ログインページにリダイレクトするように実装しています。
動作確認
ログイン情報の状態をChromeのデベロッパーツールで確認しながら動作確認をしていきます。
1.next devでサーバを起動。
next dev
2.ログイン画面にアクセス
Chromeで 「http://localhost:3000/login」 にアクセスします。
デベロッパーツールを開き、「Application」パネルのLocal Storageの中身を表示します。
現在は空っぽの状態です。
3.ログインと画面遷移
ログインすると画像のようにlscache-loginId
にデータが保持されています。
ホーム画面とAboutページを行き来してもlscache-loginId
は削除されず、画面遷移ができています。
4.1分後に画面遷移
1分後、画面遷移をするとログイン画面にリダイレクトし、
lscache-loginId
が削除されていることが確認できます。
以上で動作確認完了です。
最後に
localStorage
に期限を設定し、期限が切れている場合はログイン画面にリダイレクトする機能を実装していきました。
認証周りは将来的にはライブラリや認証サービスを使用するように修正するかもしれませんが、上記の技術での実装方法を記録として残します。
不備等ございましたら、ご指摘とご教授のほどお願いいたします。
ありがとうございました。