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获取用户信息、权限的流程,希望能给各位童鞋带来帮助。

本文完!

目录
相关文章
|
1天前
|
数据采集 JavaScript 前端开发
Vue框架的优缺点是什么
【7月更文挑战第5天】 Vue框架:组件化开发利于重用与扩展,响应式数据绑定简化状态管理;学习曲线平缓,生态系统丰富,集成便捷,且具性能优化手段。缺点包括社区规模相对小,类型支持不足(Vue 3.x改善),路由和状态管理需额外配置,SEO支持有限。随着发展,部分缺点正被克服。
7 1
|
1天前
|
JavaScript
Vue卸载eslint的写法,单独安装eslint,单独卸载eslint
Vue卸载eslint的写法,单独安装eslint,单独卸载eslint
|
1天前
|
JavaScript
青戈大佬安装Vue,无Eslint安装版,vue2安装,vue2无eslint,最简单配置Vue安装资料
青戈大佬安装Vue,无Eslint安装版,vue2安装,vue2无eslint,最简单配置Vue安装资料
|
1天前
|
JavaScript 前端开发 开发工具
如何学习vue框架
【7月更文挑战第5天】 - 先学HTML/CSS/JS基础和前端工程化工具(npm, webpack, Git)。 - 从Vue官方文档学习基础,包括指令、组件、响应式系统。 - 深入研究Vue Router和Vuex,掌握路由管理和状态管理。 - 学习自定义指令和Mixins,优化性能技巧。 - 实战项目练习,加入Vue社区,阅读相关资源,提升技能。 - 关注Vue生态,持续实践和创新,以适应不断发展的框架。
5 0
|
2天前
|
JavaScript 区块链
vue 自定义网页图标 favicon.ico 和 网页标题
vue 自定义网页图标 favicon.ico 和 网页标题
9 1
|
1天前
|
JavaScript
This dependency was not found:* vue/types/umd in ./src/router/index.jsTo install it, you can run
This dependency was not found:* vue/types/umd in ./src/router/index.jsTo install it, you can run
This dependency was not found:* vue/types/umd in ./src/router/index.jsTo install it, you can run
|
2天前
|
存储 JavaScript 数据安全/隐私保护
vue实战——登录【详解】(含自适配全屏背景,记住账号--支持多账号,显隐密码切换,登录状态保持)
vue实战——登录【详解】(含自适配全屏背景,记住账号--支持多账号,显隐密码切换,登录状态保持)
12 1
|
2天前
|
JavaScript
vue实战——404页面模板001——男女手电筒动画
vue实战——404页面模板001——男女手电筒动画
8 1
|
1天前
|
缓存 JavaScript 算法
vue 性能优化
vue 性能优化
10 0
|
2天前
|
JavaScript 前端开发 程序员
Vue组件化、单文件组件以及使用vue-cli(脚手架)
Vue组件化、单文件组件以及使用vue-cli(脚手架)
12 0