基于vue2 + koa 2.0的前后端登录权限和路由权限控制实践

前后台交互过程中,涉及到用户登陆权限和前端路由模块是比较复杂的模块,这里需要我们理清楚整个过程,才能把整个工程架构搭起来。其实在我之前的一篇文章(https://juejin.cn/post/6983287769426559007) 中也大体讨论过这个过程。现在我通过具体的前后端项目实例来进行梳理,目的是为了一次性弄清整个过程。本文主要是基于实例项目来讲解整个登录权限前端路由控制权限是如何做的。

1. 实现前后端登录认证

本文中的前后端登陆验证是通过 token 认证机制来实现的,基于Koa 2.0的后台框架在登陆成功之后,就会生成token,客户端拿到并保存生成的token,在下一次请求是会在请求头自动携带token,在服务端进行验证(本文是通过jwt签名验证来实现前后端身份信息的验证的)。

users.post('/login', async (ctx, next) => {
  const { name, password } = ctx.request.body;
  const validate = Validate.loginCheck({ name, password });
  if (validate) {
    ctx.throw(400, '参数错误!');
  }
  const sqlData = await model.findUserData(name, password);  // 查找用户是否存在
  if (sqlData && sqlData.length > 0) {
    // 登录后获取token值
    const userId = sqlData[0].userId;
    const token = jwtService.sign({
      userId
    });
    ctx.body = { code: 200, data: token };
  } else {
    ctx.throw(400, '登录账户或者密码错误!');
  }
})

上面的代码中,登陆成功时生成 jwt签名的token(通过jwtService.js 文件的封装的sign方法实现),那么当前端携带token 回来怎么做签名验证呢?一般的方法是通过后台本地缓存token,然后和前端携带过来的token 进行对比验证(通过jwtService.js 文件的封装的verify方法实现),本文中我们不不需要后台本地缓存token,通过签名验证来实现:

/**
 * 通过前端的取到的token 来验证并返回当前用户信息
 */
users.post('/checkToken', async (ctx, next) => {
  const { token } = ctx.request.body;
  if (!token) {
    ctx.throw(401, "请先登录账号");
  }
  let data = jwtService.verify(token);   // 通过取到的token 信息验证当前用户
  if (!data || !data.userId) {
    ctx.throw(401, "token已经过期,请重新登录");
  }
  const sqlData = await model.findUserById(data.userId);  // 查找用户是否存在
  const userList = {
    roles: [sqlData[0].roles],
    name: sqlData[0].name,
    avatar: sqlData[0].avatar
  }
  ctx.body = {
    code: 200,
    data: {
      userList
    }
  }
})
// 代码文件 jwtService.js
const jwt = require("jsonwebtoken");
const processEnv = process.env; 
const JWT_SECRET = processEnv.JWT_SECRET || "n9r5tiv5";
module.exports = {
    /**
     * 获取jwt token
     * @param data
     * @returns {*}
     */
    sign(data) {
      let config = 24 * 3600;
      let token = jwt.sign(
        {
          exp:
            Math.floor(Date.now() / 1000) + config ,
          data: data
        },
        JWT_SECRET
      );
      return token;
    },
    /**
     * 验证token,返回不是null就是通过验证
     * @param token
     * @returns {data | null}
     */
    verify(token) {
      try {
        let decode = jwt.verify(token, JWT_SECRET);
        return decode.data;
      } catch (err) {
        // 不处理err
        return null;
      }
    }
  };

2. 前端路由权限控制

我们来简单分析一下本系统路由权限逻辑:

  1. 我们通过是否有权限将路由对象区分非权限路由对象权限路由对象。初始化时,将非权限路由对象赋值给Router,同时设置权限路由中的meta对象,如:meta:{roles:[‘admin’,‘editor’]}表示该roles所拥有的路由权限;
  2. 通过用户登录成功之后返回的roles值,进行路由的匹配并生成新的路由对象;
  3. 用户成功登录并跳转到首页时,根据刚刚生成的路由对象,渲染左侧的菜单,不同的用户看到的菜单是不一样的。

基于上面前后端的登陆验证的实现,我们结合路由控制权限来分析用户在登录页面和退出页面时候的逻辑,该过程主要在路由守卫阶段来完成,即通过路由导航钩子router.beforeEach()函数确定下一步的跳转逻辑:

  • 如果用户没有登录,系统初始化页面会直接跳转到登录页面,输入用户、密码登录;

  • 如果用户已经登录成功,并且已经拿到token值,此时如果用户访问登录页面,直接定位到登录页面; 如果用户访问非登录页面,需要根据用户是否缓存有roles信息来进行不同业务逻辑:
    (1)、初始情况下,用户roles信息为空:

    1. 通过sysGetUserInfo()函数,根据token拉取用户信息;并通过store将该用户roles,name等信息存储于vuex中;
    2. 通过store.dispatch(‘GenerateRoutes’, { roles })去重新过滤和生成当前用户角色对应的权限路由,通过router.addRoutes()合并路由表;
    3. 如果在获取用户信息接口时出现错误,则调取store.dispatch(‘LogOut’)接口,返回到login页面;
      (2)、用户已经拥有roles信息:

    1.点击页面路由,通过roles权限判断 hasPermission()。如果用户有该路由权限,直接跳转对应的页面;如果没有权限,则跳转至401提示页面;

核心逻辑的实现代码如下:

/**
 * 判断当前是否有路由跳转的权限
 * @param {*} roles 
 * @param {*} permissionRoles 
 * @returns 
 */
function hasPermission(roles, permissionRoles) {
  if (roles.indexOf('admin') >= 0) return true 
  if (!permissionRoles) return true
  return roles.some(role => permissionRoles.indexOf(role) >= 0)
}

router.beforeEach((to, from, next) => {
  console.log('路由守卫', to);
  NProgress.start()  // 显示页面顶部进度条
   // 设置浏览器头部标题
   const browserHeaderTitle = to.meta.title
   store.commit('SET_BROWSERHEADERTITLE', {
     browserHeaderTitle: browserHeaderTitle
   })
  // 点击登录时,拿到了token并存入了cookie,保证页面刷新时,始终可以拿到token
  if (getToken('Token')) {
    if(to.path === '/login') {
      next({ path: '/' })  
      NProgress.done() 
    } else {
      // 用户登录成功之后,每次点击路由都进行了角色的判断;
      if (store.getters.roles.length === 0) {
        let token = getToken('Token');
        sysGetUserInfo({"token": token}).then().then(res => { // 根据token拉取用户信息
          let userList = res.data.userList;
          store.commit("SET_ROLES",userList.roles);
          store.commit("SET_NAME",userList.name);
          store.commit("SET_AVATAR",userList.avatar);
          // 通过取到当前用户的权限信息,来生成权限路由表:
          store.dispatch('GenerateRoutes', { "roles":userList.roles }).then(() => { // 根据roles权限生成可访问的路由表
            router.addRoutes(store.getters.addRouters) // 动态添加可访问权限路由表
            next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
          })
        }).catch((err) => {
          store.dispatch('LogOut').then(() => {
            Message.error(err || 'Verification failed, please login again')
            next({ path: '/' })
          })
        })
      } else {
        // 没有动态改变权限的需求可直接next() 删除下方权限判断 ↓
        if (hasPermission(store.getters.roles, to.meta.roles)) {
          next()//
        } else {
          next({ path: '/401', replace: true, query: { noGoBack: true }})
        }
      }
    }
  } else {
    // 没有取到token,且路由是 /login
    if (['/login'].indexOf(to.path) !== -1) {
      next()
    } else {
      next('/login')
      NProgress.done()
    }
  }
})

本文前后端源码:

  • 前端github地址:https://github.com/llz1990/llz-vue-frontend
  • 后端github地址:https://github.com/llz1990/llz-koa-server

本文掘金链接:

  • https://juejin.cn/post/7054455089968185380
  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
"ruoyi-基于springboot vue的前后分离权限管理系统.zip" 是一个基于SpringBoot和Vue的前后分离的权限管理系统。以下是对该系统的详细说明: 这个系统是一个完全分离前后的架构,使用了现代化的前技术Vue.js和后框架SpringBoot。它的设计目标是实现一个可靠、安全、易用的权限管理系统。 系统的前部分使用Vue.js库进行开发,它充分利用了Vue.js的组件化和响应式特性,从而提供了一个良好的用户界面和交互体验。前页面可以动态地响应用户的操作,并与后进行数据交互。通过Vue-router插件,系统实现了页面的路由功能,使用户能够方便地在不同的页面之间进行切换和导航。此外,系统还使用了Element UI库,该库提供了丰富的组件和样式,可以大大提高开发效率。 系统的后部分使用了SpringBoot框架,它是一种快速开发Java应用程序的框架。SpringBoot具有自动配置、快速启动、约定大于配置等特点,可以让开发人员更专注于业务逻辑的实现。后部分负责处理前发送的请求,并进行权限验证、数据查询和操作等后逻辑。同时,系统还使用了MyBatis框架来操作数据库,它是一种简化了数据库访问的框架,能够有效地提高数据库操作的效率。 此外,系统还具有权限管理的功能。它能够根据不同的角色对用户进行权限控制,实现用户的分级管理和权限的授权。系统管理员可以在后台管理界面对用户进行管理,并配置他们的角色和权限。通过这种方式,可以保护系统的安全性,并限制用户对敏感数据的访问。 总之,ruoyi-基于springboot vue的前后分离权限管理系统.zip 是一个功能强大且易于使用的权限管理系统,它综合运用了SpringBoot和Vue.js的优势,提供了一个完整的前后分离架构,可以满足不同应用场景下的权限管理需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值