Vue项目实战(07)- 登录权限分析

简介: Vue项目实战(07)- 登录权限分析

1. 引言

在前面的章节,已经讲解了部分vue-element-admin的知识:

本文来分析vue-element-admin的登录权限分析。

2. 思路

首先来分析一下常规的登录流程:

  1. 首先用户填写完账号和密码后向服务端验证是否正确,验证通过之后,服务端会返回一个token
  2. 拿到token之后,将token存贮到cookie中,保证刷新页面后能记住用户登录状态
  3. 前端会根据token再去拉取一个 user_info的接口来获取用户的详细信息(如用户权限,用户名等等信息)。

权限流程:

  • 通过token获取用户对应的role,动态根据用户的 role算出其对应有权限的路由,通过router.addRoutes 动态挂载这些路由。

3. 流程分析

3.1 token获取分析

3.1.1 界面层

首先我们找到登录页面的对应的文件(src/views/login/index.vue),Login按钮的代码块如下:

<el-button :loading="loading" type="primary" style="width:100%;margin-bottom:30px;" @click.native.prevent="handleLogin">Login</el-button>

可以看到点击之后会调用handleLogin方法,看看handleLogin方法:

handleLogin() {
      this.$refs.loginForm.validate(valid => {
        if (valid) {
          this.loading = true
          this.$store.dispatch('user/login', this.loginForm)
            .then(() => {
              this.$router.push({ path: this.redirect || '/', query: this.otherQuery })
              this.loading = false
            })
            .catch(() => {
              this.loading = false
            })
        } else {
          console.log('error submit!!')
          return false
        }
      })
    },

3.1.2 store层

根据 this.$store.dispatch('user/login', this.loginForm)定位action代码(文件位置:src/store/modules/user.js),登录代码块内容如下,可以看得出走的是异步:

login({ commit }, userInfo) {
    const { username, password } = userInfo
    return new Promise((resolve, reject) => {
      login({ username: username.trim(), password: password }).then(response => {
        const { data } = response
        commit('SET_TOKEN', data.token)
        setToken(data.token)
        resolve()
      }).catch(error => {
        reject(error)
      })
    })
  },

里面的login就是登录了(文件:src/api/user.js),登录代码如下:

export function login(data) {
  return request({
    url: '/vue-element-admin/user/login',
    method: 'post',
    data
  })
}

3.1.3 响应内容处理

在上面的步骤,可以看得出登录成功后,根据返回的内容进行了如下操作:

response => {
   const { data } = response // 把响应内容赋值给data
   commit('SET_TOKEN', data.token) 
   setToken(data.token)
   resolve()
}

① commit(‘SET_TOKEN’, data.token):这里使用vuex来存储返回的token,具体存储的代码片段如下:

const mutations = {
  SET_TOKEN: (state, token) => {
    state.token = token
  },

② setToken(data.token):这里的setToken调用的是auth.jssrc/utils/auth.js)里面的方法,即存到cookieauth.js内容如下:

import Cookies from 'js-cookie'
const TokenKey = 'Admin-Token'
export function getToken() {
  return Cookies.get(TokenKey)
}
export function setToken(token) {
  return Cookies.set(TokenKey, token)
}
export function removeToken() {
  return Cookies.remove(TokenKey)
}

③ resolve():resolve函数是可以改变promise状态的一个函数,如果不调用此函数,那么promise的状态会一直是pending,调用之后的状态是resolved 详细解析可以参考:

3.2 权限分析

3.2.1 界面层

我们继续看看登录代码块(src/views/login/index.vue),可以看到登录成功后会跳转到首页:

首页路由定义(src/router/index.js

可以看到首页页面地址在/views/dashboard/index,这里先不看首页里面的代码,我们看看permission.js里面定义的全局钩子函数。

3.2.2 全局钩子函数

permission.js在项目的入口main.js已经被引用了,里面定义了一个钩子函数beforeEach,它是一个路由拦截,在进入界面前做一些限制,我们可以在这里根据已存储的token获取用户的基本信息,如权限。核心代码片段如下:

router.beforeEach(async(to, from, next) => {
  // start progress bar
  NProgress.start()
  // set page title
  document.title = getPageTitle(to.meta.title)
  // determine whether the user has logged in
  const hasToken = getToken()
  if (hasToken) {
    if (to.path === '/login') {
      // if is logged in, redirect to the home page
      next({ path: '/' })
      NProgress.done() // hack: https://github.com/PanJiaChen/vue-element-admin/pull/2939
    } else {
      // determine whether the user has obtained his permission roles through getInfo
      const hasRoles = store.getters.roles && store.getters.roles.length > 0
      if (hasRoles) {
        next()
      } else {
        try {
          // get user info
          // note: roles must be a object array! such as: ['admin'] or ,['developer','editor']
          const { roles } = await store.dispatch('user/getInfo')
          // generate accessible routes map based on roles
          const accessRoutes = await store.dispatch('permission/generateRoutes', roles)
          // dynamically add accessible routes
          router.addRoutes(accessRoutes)
          // hack method to ensure that addRoutes is complete
          // set the replace: true, so the navigation will not leave a history record
          next({ ...to, replace: true })
        } catch (error) {
          // remove token and go to login page to re-login
          await store.dispatch('user/resetToken')
          Message.error(error || 'Has Error')
          next(`/login?redirect=${to.path}`)
          NProgress.done()
        }
      }
    }
  } else {
    /* has no token*/
    if (whiteList.indexOf(to.path) !== -1) {
      // in the free login whitelist, go directly
      next()
    } else {
      // other pages that do not have permission to access are redirected to the login page.
      next(`/login?redirect=${to.path}`)
      NProgress.done()
    }
  }
})

上面代码块的主要逻辑如下:

  • 判断是否有token
  • 判断是否有权限roles
  • 如果没有权限roles则异步调用store里的getInfogenerateRoutes方法。

getInfo代码如下(src/store/modules/user.js:

getInfo({ commit, state }) {
    return new Promise((resolve, reject) => {
      getInfo(state.token).then(response => {
        const { data } = response
        if (!data) {
          reject('Verification failed, please Login again.')
        }
        const { roles, name, avatar, introduction } = data
        // roles must be a non-empty array
        if (!roles || roles.length <= 0) {
          reject('getInfo: roles must be a non-null array!')
        }
        commit('SET_ROLES', roles)
        commit('SET_NAME', name)
        commit('SET_AVATAR', avatar)
        commit('SET_INTRODUCTION', introduction)
        resolve(data)
      }).catch(error => {
        reject(error)
      })
    })
  },

generateRoutes方法如下(src/store/modules/permission.js):

const actions = {
  generateRoutes({ commit }, roles) {
    return new Promise(resolve => {
      let accessedRoutes
      if (roles.includes('admin')) {
        accessedRoutes = asyncRoutes || []
      } else {
        accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
      }
      commit('SET_ROUTES', accessedRoutes)
      resolve(accessedRoutes)
    })
  }
}

3.2.3 主页

好了,在permission.js的钩子函数已经把权限存储到vuex了。下面我们看看主页(/views/dashboard/index)是怎么加载的,代码如下:

<template>
  <div class="dashboard-container">
    <component :is="currentRole" />
  </div>
</template>
<script>
import { mapGetters } from 'vuex'
import adminDashboard from './admin'
import editorDashboard from './editor'
export default {
  name: 'Dashboard',
  components: { adminDashboard, editorDashboard },
  data() {
    return {
      currentRole: 'adminDashboard'
    }
  },
  computed: {
    ...mapGetters([
      'roles'
    ])
  },
  created() {
    if (!this.roles.includes('admin')) {
      this.currentRole = 'editorDashboard'
    }
  }
}
</script>

可以看到有一个...mapGetter里面就是获取roles权限的代码了。在created钩子函数可以看到做了一些逻辑处理,即如果当前的权限不包含admin管理员,dashboard则走编辑者模式。

4. 小结

本文主要分析并讲解了vue-element-admin的登录获取token,以及根据token获取用户信息、权限的流程,希望能给各位童鞋带来帮助。

本文完!

目录
相关文章
|
9天前
|
JavaScript
vue实现任务周期cron表达式选择组件
vue实现任务周期cron表达式选择组件
59 4
|
30天前
|
SQL JavaScript 前端开发
Vue实现动态数据透视表(交叉表)
Vue实现动态数据透视表(交叉表)
156 13
|
1月前
|
数据采集 资源调度 JavaScript
极致的灵活度满足工程美学:用Vue Flow绘制一个完美流程图
本文介绍了使用 Vue Flow 绘制流程图的方法与技巧。Vue Flow 是一个灵活强大的工具,适合自定义复杂的流程图。文章从环境要求(Node.js v20+ 和 Vue 3.3+)、基础入门案例、自定义功能(节点与连线的定制、事件处理)到实际案例全面解析其用法。重点强调了 Vue Flow 的高度灵活性,虽然预定义内容较少,但提供了丰富的 API 支持深度定制。同时,文中还分享了关于句柄(handles)的使用方法,以及如何解决官网复杂案例无法运行的问题。最后通过对比 mermaid,总结 Vue Flow 更适合需要高度自定义和复杂需求的场景,并附带多个相关技术博客链接供进一步学习。
|
1月前
|
存储 数据采集 供应链
属性描述符初探——Vue实现数据劫持的基础
属性描述符还有很多内容可以挖掘,比如defineProperty与Proxy的区别,比如vue2与vue3实现数据劫持的方式有什么不同,实现效果有哪些差异等,这篇博文只是入门,以后有时间再深挖。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
4月前
|
JavaScript
vue使用iconfont图标
vue使用iconfont图标
211 1
|
1月前
|
JavaScript 前端开发 算法
vue渲染页面的原理
vue渲染页面的原理
128 56
|
2月前
|
移动开发 JavaScript API
Vue Router 核心原理
Vue Router 是 Vue.js 的官方路由管理器,用于实现单页面应用(SPA)的路由功能。其核心原理包括路由配置、监听浏览器事件和组件渲染等。通过定义路径与组件的映射关系,Vue Router 将用户访问的路径与对应的组件关联,支持哈希和历史模式监听 URL 变化,确保页面导航时正确渲染组件。
|
2月前
|
监控 JavaScript 前端开发
ry-vue-flowable-xg:震撼来袭!这款基于 Vue 和 Flowable 的企业级工程项目管理项目,你绝不能错过
基于 Vue 和 Flowable 的企业级工程项目管理平台,免费开源且高度定制化。它覆盖投标管理、进度控制、财务核算等全流程需求,提供流程设计、部署、监控和任务管理等功能,适用于企业办公、生产制造、金融服务等多个场景,助力企业提升效率与竞争力。
174 12
|
2月前
|
JavaScript 前端开发 开发者
Vue中的class和style绑定
在 Vue 中,class 和 style 绑定是基于数据驱动视图的强大功能。通过 class 绑定,可以动态更新元素的 class 属性,支持对象和数组语法,适用于普通元素和组件。style 绑定则允许以对象或数组形式动态设置内联样式,Vue 会根据数据变化自动更新 DOM。
|
2月前
|
JavaScript 前端开发 数据安全/隐私保护
Vue Router 简介
Vue Router 是 Vue.js 官方的路由管理库,用于构建单页面应用(SPA)。它将不同页面映射到对应组件,支持嵌套路由、路由参数和导航守卫等功能,简化复杂前端应用的开发。主要特性包括路由映射、嵌套路由、路由参数、导航守卫和路由懒加载,提升性能和开发效率。安装命令:`npm install vue-router`。