vue-element-admin登录 / 注销 / 权限验证 篇

裤衩大佬:不同的权限对应着不同的路由,同时侧边栏也需根据不同的权限,异步生成。

链接:https://juejin.im/post/591aa14f570c35006961acac

下述所有的数据和操作都是通过vuex全局管理控制的。补充说明:刷新页面后 vuex的内容也会丢失,所以需要重复上述的那些操作

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

路径:src/views/login/index.vue
https://github.com/PanJiaChen/vue-element-admin/blob/master/src/views/login/index.vue

登录事件
<el-input @keyup.enter.native="handleLogin"/> <!-- 键修饰符,键别名  @keyup.enter-->
<el-button @click.native.prevent="handleLogin">Login</el-button> //.native - 监听组件根元素的原生事件。

//触发登录操作
this.$store.dispatch('user/login', this.loginForm).then(() => {
  this.$router.push({ path: '/' }); //登录成功之后重定向到首页
}).catch(err => {
  this.$message.error(err); //登录失败提示错误
});

// Vuex 操作
const actions = {
  // user login
  login({ commit }, userInfo) {
    const { username, password } = userInfo
    return new Promise((resolve, reject) => {
    // 请求接口 获取其用户对应的 token
      login({ username: username.trim(), password: password }).then(response => {
        const { data } = response
        commit('SET_TOKEN', data.token)
        setToken(data.token) // setToken() 方法是将token 存进cookies 中
        resolve()
      }).catch(error => {
        reject(error)
      })
    })
  },
 }

登录成功后,服务端会返回一个 token(该token的是一个能唯一标示用户身份的一个key),之后我们将token存储在本地cookie之中,这样下次打开页面或者刷新页面的时候能记住用户的登录状态,不用再去登录页面重新登录了。

获取用户信息

用户登录成功之后,我们会在全局钩子router.beforeEach中拦截路由,判断是否已获得token,在获得token之后我们就要去获取用户的基本信息了

//router.beforeEach
if (store.getters.roles.length === 0) { // 判断当前用户是否已拉取完user_info信息
  store.dispatch('GetInfo').then(res => { // 拉取user_info
    const roles = res.data.role;
    next();//resolve 钩子
  })

还记得上面的 补充说明么? 刷新页面后 vuex的内容也会丢失,所以需要重复上述的那些操作

一旦用户 刷新页面之后 Vuex 中的数据会丢失,哪么 vue-element-admin 中是怎么处理的

  • 首先账号密码登录之后获取其token,并且存入Cookies 中
  • 当页面刷新之后,token从Cookies 中重新获取,然后重新拉取 user_info 信息,所以在 Vuex 中的actions 重新带上 token 去请求 , Vuex 中 actionsmutation 之间的区别自行百度
const getDefaultState = () => {
  return {
    token: Cookies.get(TokenKey),
    name: '',
    avatar: ''
  }
}

const actions = {
  // get user info
  getInfo({ commit, state }) {
    return new Promise((resolve, reject) => {
      getInfo(state.token).then(response => {
        const { data } = response
        console.log('user_login_data') // 每次刷新页面之后 都会重新打印一次
        if (!data) {
          reject('Verification failed, please Login again.')
        }
        const { name, avatar } = data
        commit('SET_NAME', name)
        commit('SET_AVATAR', avatar)
        resolve(data)
      }).catch(error => {
        reject(error)
      })
    })
  },
}

但是刷新页面之后 ,该项目中再次请求接口的状态码是 304,大家可以百度一下 304的含义

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IGwNK7Ho-1587432218959)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200420215906875.png)]

裤衩大佬:ps:为了保证安全性,我司现在后台所有token有效期(Expires/Max-Age)都是Session,就是当浏览器关闭了就丢失了。重新打开游览器都需要重新登录验证,后端也会在每周固定一个时间点重新刷新token,让后台用户全部重新登录一次,确保后台用户不会因为电脑遗失或者其它原因被人随意使用账号。

就如前面所说的,我只在本地存储了一个用户的token,并没有存储别的用户信息(如用户权限,用户名,用户头像等)。有些人会问为什么不把一些其它的用户信息也存一下?主要出于如下的考虑:

假设我把用户权限和用户名也存在了本地,但我这时候用另一台电脑登录修改了自己的用户名,之后再用这台存有之前用户信息的电脑登录,它默认会去读取本地 cookie 中的名字,并不会去拉去新的用户信息。

所以现在的策略是:页面会先从 cookie 中查看是否存有 token,没有,就走一遍上一部分的流程重新登录,如果有token,就会把这个 token 返给后端去拉取user_info,保证用户信息是最新的。 当然如果是做了单点登录得功能的话,用户信息存储在本地也是可以的。当你一台电脑登录时,另一台会被提下线,所以总会重新登录获取最新的内容。

而且从代码层面我建议还是把 loginget_user_info两件事分开比较好,在这个后端全面微服务的年代,后端同学也想写优雅的代码~

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

权限篇具体实现

1.创建vue实例的时候将vue-router挂载,但这个时候vue-router挂载一些登录或者不用权限的公用的页面。

2.当用户登录后,获取用role,将role和路由表每个页面的需要的权限作比较,生成最终用户可访问的路由表。

3.调用router.addRoutes(store.getters.addRouters)添加用户可访问的路由。

4.使用vuex管理路由表,根据vuex中可访问的路由渲染侧边栏组件。

注意事项:这里有一个需要非常注意的地方就是 404 页面一定要最后加载,如果放在constantRouterMap一同声明了404,后面的所以页面都会被拦截到404

Logo

前往低代码交流专区

更多推荐