RBAC前端架构-06:使用localstorage及Vuex用户信息存储逻辑

1-文件调整

  1. 修改frontend-vue2\src\store\index.js,用于整体整合Vuex更简洁
js 复制代码
import Vue from "vue";
import Vuex from "vuex";

// 标签页管理模块
import tabs from "./modules/tabs";
// 用户信息管理模块
import user from "./modules/user";

Vue.use(Vuex);

// 创建并导出 Vuex store 实例
export default new Vuex.Store({
  // 模块化配置 - 将 store 分割成不同的模块
  modules: {
    // 所有user的commit/dispatch都要加命名空间,如: this.$store.dispatch("user/logout");
    user,
    // 后续扩展...
  },
});
  1. 新增frontend-vue2\src\store\modules\user.js,用于控制用户相关的信息,结合localstorage,配合Vuex存储用户的token,基本信息,菜单,权限信息,后续便于其他地方使用
js 复制代码
import { loginApi, logoutApi } from "@/api/auth";
import { getCurrentUserMenus, getUserInfo } from "@/api/user";
import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

// 页面刷新时从 localStorage 里恢复用户状态
const savedToken = localStorage.getItem("token");
const savedUserInfo = localStorage.getItem("userInfo");
const savedUserMenus = localStorage.getItem("userMenus");
const savedUserPermissions = localStorage.getItem("userPermissions");

const state = {
  // 全局状态:存储用户 token
  token: savedToken || null,
  // 用户信息
  userInfo: savedUserInfo ? JSON.parse(savedUserInfo) : null,
  // 全局loading信息,用于调用接口时显示 loading
  loading: false,
  // 当前用户的权限码
  userPermissions: savedUserPermissions ? JSON.parse(savedUserPermissions) : [],
  // 当前用户的菜单树
  userMenus: savedUserMenus ? JSON.parse(savedUserMenus) : [],
};

// mutations:修改state的唯一入口
const mutations = {
  // 设置 token(登录时调用)
  setToken(state, token) {
    state.token = token;
    localStorage.setItem("token", token);
  },
  // 清除 token(退出时调用)
  clearToken(state) {
    state.token = null;
    localStorage.removeItem("token");
  },
  // 设置用户信息
  setUserInfo(state, userInfo) {
    state.userInfo = userInfo;
    localStorage.setItem("userInfo", JSON.stringify(userInfo));
  },
  // 清除用户信息
  clearUserInfo(state) {
    state.userInfo = null;
    localStorage.removeItem("userInfo");
  },
  setUserPermissions(state, userPermissions) {
    state.userPermissions = userPermissions;
    localStorage.setItem("userPermissions", JSON.stringify(userPermissions));
  },
  clearUserPermissions(state) {
    state.userPermissions = [];
    localStorage.removeItem("userPermissions");
  },
  setUserMenus(state, userMenus) {
    state.userMenus = userMenus;
    localStorage.setItem("userMenus", JSON.stringify(userMenus));
  },
  clearUserMenus(state) {
    state.userMenus = [];
    localStorage.removeItem("userMenus");
  },
  // 控制 loading 显示开关
  setLoading(state, flag) {
    state.loading = flag;
  },
};

// actions:处理异步逻辑(像 Java Service 层)
const actions = {
  async login({ commit }, { username, password }) {
    try {
      // 登录获取token
      const res = await loginApi({ username, password });
      // 登录失败,抛错
      if (res.code !== "200") {
        throw new Error(res.message || "登录失败");
      }
      commit("setToken", res.data);
      // 登录成功后获取用户信息
      const userInfo = await getUserInfo();
      commit("setUserInfo", userInfo.data);
      // 登录成功后获取用户权限
      // TODO可以拆一个权限接口
      commit("setUserPermissions", userInfo.data.permissions || []);
      // 登录成功后获取用户的菜单信息
      const userMenus = await getCurrentUserMenus();
      commit("setUserMenus", userMenus.data || []);
    } catch (err) {
      throw err;
    }
  },
  // 退出登录
  async logout({ commit }, skipApiCall = false) {
    try {
      commit("setLoading", true);
      // 只有在主动触发 logout 时才调用 API
      if (!skipApiCall) {
        await logoutApi();
      }
    } catch (error) {
      console.error("Logout API error:", error);
    } finally {
      commit("clearToken");
      commit("clearUserInfo");
      commit("clearUserMenus");
      commit("clearUserPermissions");
      commit("setLoading", false);
    }
  },
};

// getters:数据的派生计算
const getters = {
  // 获取登录状态:是否有 token
  isLoggedIn: (state) => !!state.token,
  // 获取用户信息
  userInfo: (state) => state.userInfo,
  // 获取用户角色
  roles: (state) => state.userInfo?.roles || [],
  // 获取用户权限
  permissions: (state) => state.userPermissions || [],
  // 检查是否有某个权限
  hasPermission: (state) => (permission) => {
    return state.userPermissions?.includes(permission) || false;
  },
  // 检查是否有某个角色
  hasRole: (state) => (role) => {
    return state.userInfo?.roles?.includes(role) || false;
  },
  // 获取用户菜单
  userMenus: (state) => state.userMenus || [],
  // 页面loading状态
  isLoading: (state) => state.loading,
};

// 导出这个 Vuex 模块的配置
export default {
  // 开启命名空间,防止不同模块间的状态冲突
  namespaced: true,
  state,
  mutations,
  actions,
  getters,
};

主要作用:

  • 状态管理 (State): 存储 token、用户信息、权限列表、菜单树以及全局加载状态。
  • 持久化: 初始化时自动从 localStorage 读取数据,更新时同步写入,确保页面刷新后登录状态不丢失
  • 异步流 (Actions): 封装了复杂的登录逻辑(登录 -> 获取用户信息 -> 获取菜单/权限)和登出逻辑。
  • 数据派生 (Getters): 提供快捷的权限判断方法(如 hasPermission),方便在组件中直接使用

2-结构展示

获取对应接口响应的信息,然后存储

  • token:

    eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIiwiaWF0IjoxNzcwNzc3OTYwLCJleHAiOjE3NzA4NjQzNjB9.GxtIfTMJ_fot4VodLEdQPFeFuiTZ-PQWHfo0dN6GVco

  • userInfo:

json 复制代码
{"id":1,"username":"admin","nickname":"管理员Main","email":"999999999@qq.com","phone":"13983999999","status":1,"createTime":"2025-09-23T07:19:52","updateTime":"2026-01-23T08:17:59","roles":["ADMIN"],"permissions":["btn:user:system:menu:create","btn:user:system:menu:delete","btn:permission:assign","btn:user:create","btn:user:update","btn:user:delete","btn:user:list"]}
  • userMenus:
json 复制代码
[{"id":5,"menuName":"系统管理","menuCode":"menu:user:system","menuType":1,"parentId":null,"path":"/system","component":"","icon":"","sortOrder":0,"status":1,"createTime":"2025-10-24T03:58:06","updateTime":"2025-10-31T08:56:10","children":[{"id":4,"menuName":"个人中心","menuCode":"menu:user:system:profile","menuType":1,"parentId":5,"path":"/system/profile","component":"Profile","icon":"user","sortOrder":0,"status":1,"createTime":"2025-10-24T03:58:06","updateTime":"2025-10-31T08:55:57","children":[]},{"id":6,"menuName":"权限分配","menuCode":"menu:user:system:permissionassign","menuType":1,"parentId":5,"path":"/system/permissionsAssign","component":"PermissionsAssign","icon":"","sortOrder":0,"status":1,"createTime":null,"updateTime":"2025-11-19T07:01:24","children":[]},{"id":1,"menuName":"用户管理","menuCode":"menu:user:system:user","menuType":1,"parentId":5,"path":"/system/user","component":"UserManagement","icon":"user","sortOrder":1,"status":1,"createTime":"2025-10-24T03:58:06","updateTime":"2025-10-31T08:55:57","children":[]},{"id":3,"menuName":"菜单管理","menuCode":"menu:user:system:menu","menuType":1,"parentId":5,"path":"/system/menu","component":"MenuManagement","icon":"setting","sortOrder":3,"status":1,"createTime":"2025-10-24T03:58:06","updateTime":"2025-10-31T08:55:57","children":[]}]},{"id":2,"menuName":"订单管理","menuCode":"menu:order","menuType":1,"parentId":null,"path":"/order","component":"OrderManagement","icon":"tickets","sortOrder":2,"status":1,"createTime":"2025-10-24T03:58:06","updateTime":"2025-10-30T04:18:39","children":[]}]
  • userPermissions:
json 复制代码
["btn:user:system:menu:create","btn:user:system:menu:delete","btn:permission:assign","btn:user:create","btn:user:update","btn:user:delete","btn:user:list"]

以上信息主要用于让其他组件获取使用,比如后续菜单的展示,就用userMenus中的信息

相关推荐
BUG集结者2 小时前
【Navigation3】结合ViewModel(二)
前端
用户80806181436932 小时前
JavaScript 异步编程完全指南:从入门到精通
前端
凯里欧文4272 小时前
CSS Grid 案例
前端·css
天若有情6732 小时前
Vuex 的核心作用深度解析:构建高效可维护的 Vue 应用状态管理体系
前端·javascript·vue.js·vuex
哆啦A梦15882 小时前
Vue3魔法手册 作者 张天禹 015_插槽
前端·vue.js·typescript·vue3
lisypro12 小时前
gin-vue-admin项目使用命令行进行启动
前端·vue.js·golang·gin
Ziky学习记录2 小时前
深入理解 JavaScript 事件循环机制
前端·javascript
码云数智-园园2 小时前
React Server Components 深度解析与实战应用:从原理到生产级落地指南
开发语言·前端·javascript
lyyl啊辉2 小时前
5. pinia集中状态存储
vue.js