Vue.js | 権限管理とユーザー管理機能の追加について

はじめに

権限管理とユーザー管理は、多くのシステムにおいて不可欠な要素です。本記事では、既存の「メールアカウント申請システム」に権限管理とユーザー管理機能を追加したプロセスを紹介します。
この機能追加により、システム管理者が他のユーザーの管理を行えるようになり、セキュリティ性と管理性が向上しました。


機能概要

1. 権限管理

権限管理は、以下の2つの役割を定義しました。

  • 一般ユーザー(user): メールアカウントの申請・確認が可能。
  • 管理者(admin): メールアカウント申請の管理に加え、システム内の他ユーザーの管理も可能。

権限管理は以下の方法で実装しました。

  • セッション管理: サーバー側でセッションを利用し、ログインユーザーの権限情報を保存。
  • フロントエンドの制御: 権限に基づいてナビゲーションや機能の表示を動的に切り替え。

2. ユーザー管理機能

管理者は以下の操作を実行可能です。

  • ユーザー一覧の表示。
  • 各ユーザーの権限(admin または user)の変更。

実装の詳細

バックエンド:権限管理の追加

セッション管理を利用した権限判定

UserControllerに以下のコードを追加しました。ログイン後、ユーザーの権限情報をセッションに保存し、必要に応じて利用します。

public function login() {
    $data = json_decode(file_get_contents('php://input'), true);
    $email = $data['email'] ?? null;
    $password = $data['password'] ?? null;

    if (!$email || !$password) {
        http_response_code(400);
        echo json_encode(['success' => false, 'message' => 'メールアドレスとパスワードを入力してください。']);
        return;
    }

    try {
        $stmt = $this->db->prepare("SELECT id, password_hash, role FROM users WHERE email = :email");
        $stmt->execute([':email' => $email]);
        $user = $stmt->fetch(PDO::FETCH_ASSOC);

        if ($user && password_verify($password, $user['password_hash'])) {
            session_start();
            $_SESSION['user_id'] = $user['id'];
            $_SESSION['user_role'] = $user['role'];

            echo json_encode(['success' => true, 'message' => 'ログイン成功']);
        } else {
            http_response_code(401);
            echo json_encode(['success' => false, 'message' => '認証に失敗しました。']);
        }
    } catch (PDOException $e) {
        http_response_code(500);
        echo json_encode(['success' => false, 'message' => 'サーバーエラーが発生しました。']);
    }
}

フロントエンド:ナビゲーションとロール管理

ナビゲーションの制御

フロントエンドでは、ログインユーザーのロールに基づいてナビゲーションバーを動的に変更しました。

app.component('nav-bar', {
  template: `
    <nav class="bg-gray-800 text-white py-4">
      <ul class="flex justify-center space-x-4">
        <li><router-link to="/application" class="hover:underline">申請作成</router-link></li>
        <li><router-link to="/status" class="hover:underline">申請状況</router-link></li>
        <li v-if="isAdmin"><router-link to="/admin/applications" class="hover:underline">管理者用申請一覧</router-link></li>
        <li v-if="isAdmin"><router-link to="/admin/users" class="hover:underline">ユーザー管理</router-link></li>
        <li v-if="isLoggedIn" class="hover:underline cursor-pointer" @click="logout">ログアウト</li>
        <li v-if="!isLoggedIn"><router-link to="/login" class="hover:underline">ログイン</router-link></li>
      </ul>
    </nav>
  `,
  props: ['isLoggedIn', 'userRole'],
  computed: {
    isAdmin() {
      return this.userRole === 'admin'; // 管理者権限の判定
    },
  },
  methods: {
    logout() {
      this.$emit('logout'); // ログアウト処理
    },
  },
});

ユーザー管理画面の実装

管理者用のユーザー管理画面を実装しました。以下はそのコードです。

export default {
  template: `
    <div class="max-w-4xl mx-auto bg-white shadow-lg rounded-lg p-6 mt-10">
      <h2 class="text-2xl font-bold mb-4 text-gray-800">ユーザー管理</h2>
      <div v-if="loading" class="text-center">読み込み中...</div>
      <div v-else>
        <table class="table-auto w-full border-collapse border border-gray-300">
          <thead>
            <tr class="bg-gray-100">
              <th class="border border-gray-300 px-4 py-2">ユーザーID</th>
              <th class="border border-gray-300 px-4 py-2">名前</th>
              <th class="border border-gray-300 px-4 py-2">メールアドレス</th>
              <th class="border border-gray-300 px-4 py-2">権限</th>
              <th class="border border-gray-300 px-4 py-2">操作</th>
            </tr>
          </thead>
          <tbody>
            <tr v-for="user in users" :key="user.id">
              <td class="border border-gray-300 px-4 py-2">{{ user.id }}</td>
              <td class="border border-gray-300 px-4 py-2">{{ user.name }}</td>
              <td class="border border-gray-300 px-4 py-2">{{ user.email }}</td>
              <td class="border border-gray-300 px-4 py-2">{{ translateRole(user.role) }}</td>
              <td class="border border-gray-300 px-4 py-2">
                <select v-model="user.role" @change="updateRole(user.id, user.role)">
                  <option value="user">ユーザー</option>
                  <option value="admin">管理者</option>
                </select>
              </td>
            </tr>
          </tbody>
        </table>
      </div>
    </div>
  `,
  data() {
    return {
      users: [],
      loading: true,
    };
  },
  methods: {
    translateRole(role) {
      return role === 'admin' ? '管理者' : 'ユーザー';
    },
    async fetchUsers() {
      try {
        const response = await fetch('/api/admin/users', { credentials: 'include' });
        const data = await response.json();
        if (data.success) {
          this.users = data.users;
        } else {
          alert('ユーザー一覧の取得に失敗しました: ' + data.message);
        }
      } catch (error) {
        console.error('エラー:', error);
      } finally {
        this.loading = false;
      }
    },
    async updateRole(userId, newRole) {
      try {
        const response = await fetch('/api/admin/users/update-role', {
          method: 'PUT',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ user_id: userId, role: newRole }),
        });
        const data = await response.json();
        if (!data.success) {
          alert('権限の更新に失敗しました: ' + data.message);
        }
      } catch (error) {
        console.error('エラー:', error);
      }
    },
  },
  async created() {
    this.fetchUsers();
  },
};

まとめ

権限管理とユーザー管理機能を追加したことで、システムのセキュリティ性と柔軟性が向上しました。特に、セッションベースでの権限管理を採用することで、セキュリティ面でのリスクを最小化しつつ、使いやすい管理画面を提供しました。

コメント

タイトルとURLをコピーしました