Vuex を使ったセッションタイムアウト処理を実装

Vuex を使ったセッションタイムアウトの処理を実装した時のメモ。

Vuex ストアの設定

以下のコードを store/index.js に記述します。

import { createStore } from 'vuex';
import router from '@/router';

export default createStore({
  state: {
    lastActiveTime: Date.now(), // 最後の操作時刻
    timeoutDuration: 30 * 60 * 1000, // タイムアウト時間(30分)
    timer: null, // タイマー管理
  },
  mutations: {
    updateLastActiveTime(state) {
      state.lastActiveTime = Date.now();
    },
    startTimer(state, timer) {
      state.timer = timer;
    },
    clearTimer(state) {
      if (state.timer) {
        clearTimeout(state.timer);
        state.timer = null;
      }
    },
  },
  actions: {
    resetTimer({ commit, state, dispatch }) {
      // 既存のタイマーをクリア
      commit('clearTimer');

      // 新しいタイマーを設定
      const timer = setTimeout(() => {
        dispatch('handleTimeout');
      }, state.timeoutDuration);

      commit('startTimer', timer);
    },
    handleTimeout({ commit }) {
      commit('clearTimer'); // タイマーをクリア
      alert('セッションがタイムアウトしました。再度ログインしてください。');
      router.push('/login'); // ログイン画面に遷移
    },
    userInteraction({ commit, dispatch }) {
      commit('updateLastActiveTime'); // 最終アクティブ時間を更新
      dispatch('resetTimer'); // タイマーをリセット
    },
  },
});

ユーザー操作の監視設定

main.js でmousemoveとkeydownのイベントリスナーを設定します。

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'

document.addEventListener('mousemove', () => store.dispatch('userInteraction'))
document.addEventListener('keydown', () => store.dispatch('userInteraction'))

createApp(App).use(store).use(router).mount('#app')

store.dispatch('resetTimer')

これにより、ユーザーの操作が行われるたびに、タイマーがリセットされ、タイムアウト時間を過ぎた場合、自動的にログイン画面にリダイレクトされます。