はじめに
今回は、Reactプロジェクトにおいて、Local Storageを用いてWebサイトにアクセスするユーザのIDを扱う方法を紹介します。なお、後述するとおり、Local Storageはセキュリティ面でのリスクが高いため、機密性の高い情報を保存することには向いていません。今回はあくまでユーザの識別にのみ利用可能であり、他に悪用することができないIDの管理について紹介します。
よりセキュアにユーザID等を管理する必要がある場合は、セキュリティ対策や認証管理を行うことができるCookieを使用する方が適切かもしれません。
Local Storageとは?
Local Storageは、JavaScriptを使用してブラウザにデータを永続的に保持するためのAPIです。
セッションストレージとは異なり、Local Storageに保存されたデータはブラウザを閉じても保持されたままとなります。ブラウザの設定からキャッシュやCookieを含むデータを削除したり、アプリケーションにて明示的にlocalStorage.clear()
を呼び出したりしない限り、Local Storage上のデータは削除されません。そのため、Webサイトを訪れるユーザの識別情報をLocal Storageで管理することで、そのユーザの操作内容の履歴等を確認することができそうです(同一人物が、たとえばChromeとEdgeでWebサイトにアクセスするとIDは2つ付与されてしまいますが、、)。
Local Storageは簡単に使用することが可能ですが、以下のようなセキュリティ上のリスクがあります。
- データが暗号化されない
- JavaScriptから自由にアクセスできる
データの盗聴が容易であり、クロスサイトスクリプティング(XSS)攻撃のリスクが高いなどの理由から、機密性の高い情報を保存するべきではありません。
実装内容
実装のポイントは、createContextとuseContextを使用してユーザID(uid)をコンテキスト化し、子コンポーネントからアクセスできるようにしている点です。これによって、どのユーザが、どの画面で、どのような操作を行ったか、というレベルのログを取得することが可能となります。
import React, {createContext, useContext, useState, useEffect} from 'react'
// 一意の識別子を生成するための関数をインポート
import {v4 as uuidv4} from 'uuid'
// コンテキストオブジェクトを作成
const UserContext = createContext()
// localStorageでユニークユーザIDを保存するためのキー
const UID_LOCAL_STORAGE_KEY = 'uid'
export default function App({children}) {
const [uid, _] = useState(() => {
// クライアントサイドでのみlocalStorageを利用する
if (typeof window !== 'undefined') {
// 初回レンダリング時にlocalStorageからuidを取得
const storedUid = localStorage.getItem(UID_LOCAL_STORAGE_KEY)
// uidがない場合は新しいuidを生成
return storedUid ? storedUid : uuidv4()
} else {
return uuidv4()
}
})
// ユーザIDが更新されるたびにLocal Storageに新しい値をセットする
useEffect(() => {
localStorage.setItem(UID_LOCAL_STORAGE_KEY, uid)
}, [uid])
return (
<html lang="ja">
<head>
・・・
</head>
<body>
<UserContext.Provider value={uid}>
<div>{children}</div>
</UserContext.Provider>
</body>
</html>
)
}
// カスタムフックを作成してコンテキストにアクセスできるようにする
export const useUserContext = () => useContext(UserContext)
子コンポーネントからは以下のようにコンテキストにアクセスすることが可能です。
import React from 'react'
import {useUserContext} from './App'
const ChildComponent = () => {
const uid = useUserContext()
// 他の処理
return (
<div>
・・・
</div>
)
}
export default ChildComponent