用户权限控制(Token登录)

1.用户权限控制

1.1 用户登录

1.1.1 流程分析

1) 用户登录界面,需要输入手机号密码

2) 登录组件 login.vue

  • 登录按钮

 
type="primary":loading="loading"@click="submit('login-form')">{{ loading ? 'Loading...' : '登录' }}

  • 提交表的方法

 
 //
提交登录表单
 submit(ref) {
      //
校验
      this.$refs[ref].validate(valid =>{
        if (!valid) return false;
 
        this.error = null;
        this.loading = true;
 
        //
发送登录请求
        this.$store.dispatch("createToken", this.model)
          .then(res =
>{
            if (res.state !==
1) {
              this.error = {
                title:
"Error occurred",
                message:
"Abnormal, please try again later!"
              };
            }
            this.$router.replace({ path: this.$route.query.redirect ||
"/"});
            this.loading = false;
          })
          .catch(err =
>{
            this.loading = false;
          });
      });
    }
  }

  • this.$store.dispatch("createToken", this.model)
    • 这段代码的意思是调用store仓库的actions.js中的createToken方法

  • 发送登录请求,进行登录的代码

 
  /**
   *
创建新的客户端令牌
   */
  createToken: async ({ commit }, { username, password }) =
>{
    //
请求后台登录接口
    const res = await TokenService.userLogin({
      phone: username.trim(),
      password: password.trim()
    });
 
    console.log(res);
 
    //
判断结果不等于1,登录失败
    if (res.state !==1) {
      return Promise.resolve(res);
    }
 
    //
获取到content
    const result = res.content;
 
    //
token保存
    commit(CHANGE_SESSION, {
      accessToken: result.access_token
    });
     
    return res;
  },

  • TokenService

 
import { TokenService, UserService } from
"../services";

 
//
登录请求async ES6语法,作用:发送异步请求
export const userLogin =  async (data) =>{
 //await
表示等待接收返回的数据
 return await PostRequest(`${process.env.VUE_APP_API_FAKE}/user/login${Serialize(data)}`)
}

1.2 动态获取用户菜单

1.2.1 流程分析

1) 在我们登录成功后, 会立即发送第二个请求, 来获取用户的菜单权限列表

2) 在actions.js 中完成请求后台接口 获取数据的操作

 
  /**
   *
获取当前登录用户权限
   */
  getUserPermissions: async ({ commit }) =
>{
    //
1.请求后台 获取当前用户的权限
    const res = await UserService.getUserPermissions();
 
    //
2.判断
    if (!res.success) {
      //
获取失败直接返回false
      return res.success;
    }
 
    //
3.获取数据成功,取出菜单 与 资源列表
    const { menuList, resourceList } = res.content;
 
    //
4.下面的代码 就是在生成树形结构的菜单
    let menus = [];
    const formatMenu = treeData =
>{
      if (treeData.length
>0) {
        return treeData.map(item =
>formatMenu(item));
      }
      const result = {};
 
      //shown
等于表示可以显示,将内容保存
      if (treeData.shown ==1) {
        result.id = treeData.id;
        result.text = treeData.name;
        result.label = treeData.name;
        result.name = treeData.href;
        result.icon = treeData.icon;
        result.shown = treeData.shown;
      } else {
        return
"";
      }
 
      //
获取子节点
      if (treeData.subMenuList) {
        result.children = [];
        treeData.subMenuList.forEach(item =
>{
          formatMenu(item) && result.children.push(formatMenu(item));
        });
 
        if (result.children.length ===
0) {
          delete result.children;
        }
      }
      return result;
    };
 
    const memusMap = {};
 
    const splapMenu = treeData =
>{
      if (treeData.length
>0) {
        return treeData.map(item =
>splapMenu(item));
      }
      const result = {};
      result.id = treeData.id;
      result.text = treeData.name;
      result.label = treeData.name;
      result.name = treeData.href;
      result.icon = treeData.icon;
      result.shown = treeData.shown;
      result.name && (memusMap[result.name] = result);
 
      if (treeData.subMenuList) {
        result.children = [];
        treeData.subMenuList.forEach(item =
>{
          result.children.push(splapMenu(item));
        });
      }
      return result;
    };
 
    splapMenu(menuList);
 
    menus = formatMenu(menuList);
    commit(CHANGE_SIDERBAR_MENU, menus);
    return { menus, resourceList, menuList, memusMap };
  },

1.3 验证Token

1.3.1 导航守卫

在执行路由之前先执行的一些钩子函数,比如验证用户是否有权限之类的操作,就需要使用.

1) authorize.js 中配置了导航守卫,来对用户的登录进行限制

 
  //
导航守卫to要访问的url, from从哪个路径跳转过来, next()放行
  router.beforeHooks.unshift((to, from, next) =>{
    //
不需要验证直接放行
    if (!to.meta.requireAuth) return next();
 
    //
需要验证token,调用store中的checkToken方法
    store.dispatch("checkToken").then(valid =>{
      //
判断是否存在token
      if (valid) {
        //
发送请求到后台,在后台再次判断token是否存在
        store.dispatch("getUserPermissions").then(res =>{
       
          if (!res) {
            //
失效 清除token
            store.dispatch(
"deleteToken");
 
            //
跳转到登录页面
            return next({ name:"ToLogin"});
          }
 
          //token
正确,导航到对应的页面
          const { memusMap } = res;
          if (memusMap.Courses && to.name ===
"Home") {
            return next();
          } else if (memusMap[to.name]) {
            return next();
          } else if (Object.keys(memusMap).length
>0) {
            return next({ name: memusMap[Object.keys(memusMap)[
0]].name });
          } else {
            next({ name:
"PermissionDenied"});
          }
        });
        return next();
      }
      // unauthorized
      console.log(
"Unauthorized");
 
      //
用户没有登录 跳转到登录页面
      next({ name:"Login", query: { redirect: to.fullPath } });
    });
  });

 
checkToken: async ({ commit, getters }) =
>{
    //
取出token
    const token = getters.session.accessToken;
 
    if (!token) {
      //
不可用
      return Promise.resolve(false);
    }
 
    return Promise.resolve(true);
  },

2) 在actions.js 中检查token是否可用

 
checkToken: async ({ commit, getters }) =
>{
    //
取出token
    const token = getters.session.accessToken;
 
    if (!token) {
      //
不可用
      return Promise.resolve(false);
    }
 
    return Promise.resolve(true);
  },


版权声明:本文为qq_38977566原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。