Vue项目前后端分离下的前端鉴权方案

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vue项目前后端分离下的前端鉴权方案相关的知识,希望对你有一定的参考价值。

参考技术A # Vue项目前后端分离下的前端鉴权方案

### 技术栈

  前端Vue全家桶,后台.net。

### 需求分析

  1. 前端路由鉴权,屏蔽地址栏入侵

  2. 路由数据由后台管理,前端只按固定规则异步加载路由

  3. 权限控制精确到每一个按钮

  4. 自动更新token

  5. 同一个浏览器只能登录一个账号

### 前端方案

> 对于需求1、2、3,采用异步加载路由方案

  1. 首先编写vue全局路由守卫

  2. 排除登录路由和无需鉴权路由

  3. 登录后请求拉取用户菜单数据

  4. 在vuex里处理菜单和路由匹配数据

  5. 将在vuex里处理好的路由数据通过`addRoutes`异步推入路由

  ```

    router.beforeEach((to, from, next) => 

      // 判断当前用户是否已拉取权限菜单

      if (store.state.sidebar.userRouter.length === 0) 

        // 无菜单时拉取

        getMenuRouter()

          .then(res => 

            let _menu = res.data.Data.ColumnDataList || [];

            // if (res.data.Data.ColumnDataList.length > 0) 

            // 整理菜单&路由数据

            store.commit("setMenuRouter", _menu);

            // 推入权限路由列表

            router.addRoutes(store.state.sidebar.userRouter);

            next(...to, replace: true );

            // 

          )

          .catch(err => 

            // console.log(err);

            // Message.error("服务器连接失败");

          );

       else 

        //当有用户权限的时候,说明所有可访问路由已生成 如访问没权限的菜单会自动进入404页面

        if (to.path == "/login") 

          next(

            name: "index"

          );

         else 

          next();

        

      

     else 

      // 无登录状态时重定向至登录 或可进入无需登录状态路径

      if (to.path == "/login" || to.meta.auth === 0) 

        next();

       else 

        next(

          path: "/login"

        );

      

    

  );

  ```

  ##### 注意

  > 我这里无需鉴权的路由直接写在router文件夹下的index.js,通过路由元信息meta携带指定标识

  ```

    

      path: "/err-404",

      name: "err404",

      meta: 

         authentication: false

      ,

      component: resolve => require(["../views/error/404.vue"], resolve)

    ,

  ```

  > 上面说到路由是根据后台返回菜单数据根据一定规则生成,因此一些不是菜单,又需要登录状态的路由,我写在router文件夹下的router.js里,在上面步骤4里处理后台返回菜单数据时,和处理好的菜单路由数据合并一同通过`addRoutes`推入。 

  这样做会有一定的被地址栏入侵的风险,但是笔者这里大多是不太重要的路由,如果你要求咳咳,可以定一份字典来和后台接口配合精确加载每一个路由。

  ```

  // 加入企业

  

    path: "/join-company",

    name: "join-company",

    component: resolve => require([`@/views/index/join-company.vue`], resolve) 

  ,

  ```

  > 在vuex中将分配的菜单数据转化为前端可用的路由数据,我是这样做的:

  管理系统在新增菜单时需要填写一个页面地址字段`Url`,前端得到后台菜单数据后根据`Url`字段来匹配路由加载的文件路径,每个菜单一个文件夹的好处是:你可以在这里拆分js、css和此菜单私有组件等

  ```

      menu.forEach(item => 

            let routerItem = 

              path: item.Url,

              name: item.Id,

              meta: 

                auth: item.Children,

              , // 路由元信息 定义路由时即可携带的参数,可用来管理每个路由的按钮操作权限

              component: resolve =>

                require([`@/views$item.Url/index.vue`], resolve) // 路由映射真实视图路径

            ;

            routerBox.push(routerItem);

        );

  ```

  > 关于如何精确控制每一个按钮我是这样做的,将按钮编码放在路由元信息里,在当前路由下匹配来控制页面上的按钮是否创建。

  菜单数据返回的都是多级结构,每个菜单下的子集就是当前菜单下的按钮权限码数组,我把每个菜单下的按钮放在此菜单的路由元信息`meta.auth`中。这样作的好处是:按钮权限校验只需匹配每个菜单路由元信息下的数据,这样校验池长度通常不会超过5个。

  ```

  created() 

    this.owner = this.$route.meta.auth.map(item => item.Code);

  

  methods: 

      matchingOwner(auth) 

        return this.owner.some(item => item === auth);

      

  

  ```

  > 需求4自动更新token,就是简单的时间判断,并在请求头添加字段来通知后台更新token并在头部返回,前端接受到带token的请求就直接更新token

  ```

  // 在axios的请求拦截器中

      let token = getSession(auth_code);

      if (token) config.headers.auth = token;

      if (tokenIsExpire(token)) 

        // 判断是否需要刷新jwt

        config.headers.refreshtoken = true;

      

  // 在axios的响应拦截器中

    if (res.headers.auth) 

      setSession(auth_code, res.headers.auth);

    

  ```

  > 对于需求5的处理比较麻烦,要跨tab页只能通过`cookie`或`local`,笔者这里不允许使用`cookie`因此采用的`localstorage`。通过打开的新页面读取`localstorage`内的`token`数据来同步多个页面的账号信息。`token`使用的`jwt`并前端md5加密。

  这里需要注意一点是页面切换要立即同步账号信息。

  > 经过需求5改造后的全局路由守卫是这样的:

  ```

function _AUTH_() 

  // 切换窗口时校验账号是否发生变化

  window.addEventListener("visibilitychange", function() 

    let Local_auth = getLocal(auth_code, true);

    let Session_auth = getSession(auth_code);

    if (document.hidden == false && Local_auth && Local_auth != Session_auth) 

      setSession(auth_code, Local_auth, true);

      router.go(0)

    

  )

  router.beforeEach((to, from, next) => 

      // 判断当前用户是否已拉取权限菜单

      if (store.state.sidebar.userRouter.length === 0) 

        // 无菜单时拉取

        getMenuRouter()

          .then(res => 

            let _menu = res.data.Data.ColumnDataList || [];

            // if (res.data.Data.ColumnDataList.length > 0) 

            // 整理菜单&路由数据

            store.commit("setMenuRouter", _menu);

            // 推入权限路由列表

            router.addRoutes(store.state.sidebar.userRouter);

            next(...to, replace: true );

            // 

          )

          .catch(err => 

            // console.log(err);

            // Message.error("服务器连接失败");

          );

       else 

        //当有用户权限的时候,说明所有可访问路由已生成 如访问没权限的菜单会自动进入404页面

        if (to.path == "/login") 

          next(

            name: "index"

          );

         else 

          next();

        

      

     else 

      // 无登录状态时重定向至登录 或可进入无需登录状态路径

      if (to.path == "/login" || to.meta.auth === 0) 

        next();

       else 

        next(

          path: "/login"

        );

      

    

  );



```

  > 经过需求5改造后的axios的请求拦截器是这样的,因为ie无法使用`visibilitychange`,并且尝试百度其他属性无效,因此在请求发出前做了粗暴处理:

  ```

  if (ie浏览器)  

      setLocal('_ie', Math.random())

      let Local_auth = getLocal(auth_code, true);

      let Session_auth = getSession(auth_code);

      if (Local_auth && Local_auth != Session_auth) 

        setSession(auth_code, Local_auth, true);

        router.go(0)

        return false

      

    

  ```

> 这里有一个小问题需要注意:因为用的`local`因此首次打开浏览器可能会有登录已过期的提示,这里相信大家都能找到适合自己的处理方案

  ###  结语

经过这些简单又好用的处理,一个基本满足需求的前后端分离前端鉴权方案就诞生啦

前后端分离全栈开发项目师徒开启,VUE+koa+MongoDB!

博客前后端分离开源项目

线上地址 http://116.62.147.91/koa2-vue/

本地运行

web 前端代码

cd web

npm install

npm run dev

server 后端代码

npm install

mongod --dbpath="database 下的 db 路径" --port="27030"

node app2.js

一、项目介绍

本项目是一款前后端分离全栈开发项目,前端采用 vue 框架构建, 后台使用 Koa2 框架构建,MongoDB 数据库,开发过程为 git 分支管理多人协作开发。 项目功能包括注册、登录、发表文章、文章评论、头像上传等功能。

二、项目架构

  1. 使用 vue 框架,以及 vue-router 构建单页面应用。

  2. 本项目通过 vue-cli 脚手架快速搭建开发环境,采用 vuex 管理登录后的用户信息,Axios 封装处理请求。

  3. 前端 UI 框架使用 Element-UI 组件库中部分功能进行快速开发。利用富文本插件实现发表文章功能。

三、预期达到的技术效果

  1. 能够熟练运用 HTML5 语义化标签+CSS3 新特性进行页面布局。

  2. 能够合理运用 sass 进行样式代码的编写。

  3. 能熟悉运用 vue.js 开发,route+vuex 工具的使用。

  4. 能熟悉运用 vue.js 中的指令和服务与后台服务进行数据交互 ,实现模块功能 。

  5. 能了解运用 Koa2 + MongoDB 搭建后台

  6. 能了解运用 git 多人协作的过程

  7. 能了解阿里云服务器部署项目

四、其他

  1. 适用人群:初掌 Vue,Koa2,MongoDB。需带领来系统了解 Vue,Koa2,MongoDB 开发流程。

  2. 教学周期:按照徒弟情况待定。

五、如何报名:

费用299,找阳叔WX:erdaori报名

以上是关于Vue项目前后端分离下的前端鉴权方案的主要内容,如果未能解决你的问题,请参考以下文章

前后端分离全栈开发项目师徒开启,VUE+koa+MongoDB!

Vue.js---实现前后端分离架构中前端页面搭建

前端大讲堂基于Vue的前后端分离实践

SpringBoot 2.x 开发案例之前后端分离鉴权

spring boot+vue前后端项目的分离(我的第一个前后端分离项目)

如何在开发时部署和运行前后端分离的JavaWe