亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

手摸手,帶你用vue擼后臺(tái) 系列二(登錄權(quán)限篇)

不知名網(wǎng)友 / 2161人閱讀

摘要:我們將登錄按鈕上綁上事件,點(diǎn)擊登錄之后向服務(wù)端提交賬號(hào)和密碼進(jìn)行驗(yàn)證。所以前端和后端權(quán)限的劃分是不太一致。側(cè)邊欄最后一個(gè)涉及到權(quán)限的地方就是側(cè)邊欄,不過(guò)在前

完整項(xiàng)目地址:vue-element-admin

系列文章:

手摸手,帶你用vue擼后臺(tái) 系列一(基礎(chǔ)篇)

手摸手,帶你用vue擼后臺(tái) 系列二(登錄權(quán)限篇)

手摸手,帶你用vue擼后臺(tái) 系列三 (實(shí)戰(zhàn)篇)

手摸手,帶你用vue擼后臺(tái) 系列四(vueAdmin 一個(gè)極簡(jiǎn)的后臺(tái)基礎(chǔ)模板)

手摸手,帶你封裝一個(gè)vue component

手摸手,帶你優(yōu)雅的使用 icon

手摸手,帶你用合理的姿勢(shì)使用webpack4(上)

手摸手,帶你用合理的姿勢(shì)使用webpack4(下)

前言
拖更有點(diǎn)嚴(yán)重,過(guò)了半個(gè)月才寫了第二篇教程。無(wú)奈自己是一個(gè)業(yè)務(wù)猿,每天被我司的產(chǎn)品虐的死去活來(lái),之前又病了一下休息了幾天,大家見(jiàn)諒。

進(jìn)入正題,做后臺(tái)項(xiàng)目區(qū)別于做其它的項(xiàng)目,權(quán)限驗(yàn)證與安全性是非常重要的,可以說(shuō)是一個(gè)后臺(tái)項(xiàng)目一開始就必須考慮和搭建的基礎(chǔ)核心功能。我們所要做到的是:不同的權(quán)限對(duì)應(yīng)著不同的路由,同時(shí)側(cè)邊欄也需根據(jù)不同的權(quán)限,異步生成。這里先簡(jiǎn)單說(shuō)一下,我實(shí)現(xiàn)登錄和權(quán)限驗(yàn)證的思路。

登錄:當(dāng)用戶填寫完賬號(hào)和密碼后向服務(wù)端驗(yàn)證是否正確,驗(yàn)證通過(guò)之后,服務(wù)端會(huì)返回一個(gè)token,拿到token之后(我會(huì)將這個(gè)token存貯到cookie中,保證刷新頁(yè)面后能記住用戶登錄狀態(tài)),前端會(huì)根據(jù)token再去拉取一個(gè) user_info 的接口來(lái)獲取用戶的詳細(xì)信息(如用戶權(quán)限,用戶名等等信息)。

權(quán)限驗(yàn)證:通過(guò)token獲取用戶對(duì)應(yīng)的 role,動(dòng)態(tài)根據(jù)用戶的 role 算出其對(duì)應(yīng)有權(quán)限的路由,通過(guò) router.addRoutes 動(dòng)態(tài)掛載這些路由。

上述所有的數(shù)據(jù)和操作都是通過(guò)vuex全局管理控制的。(補(bǔ)充說(shuō)明:刷新頁(yè)面后 vuex的內(nèi)容也會(huì)丟失,所以需要重復(fù)上述的那些操作)接下來(lái),我們一起手摸手一步一步實(shí)現(xiàn)這個(gè)系統(tǒng)。

登錄篇
首先我們不管什么權(quán)限,來(lái)實(shí)現(xiàn)最基礎(chǔ)的登錄功能。

隨便找一個(gè)空白頁(yè)面擼上兩個(gè)input的框,一個(gè)是登錄賬號(hào),一個(gè)是登錄密碼。再放置一個(gè)登錄按鈕。我們將登錄按鈕上綁上click事件,點(diǎn)擊登錄之后向服務(wù)端提交賬號(hào)和密碼進(jìn)行驗(yàn)證。
這就是一個(gè)最簡(jiǎn)單的登錄頁(yè)面。如果你覺(jué)得還要寫的更加完美點(diǎn),你可以在向服務(wù)端提交之前對(duì)賬號(hào)和密碼做一次簡(jiǎn)單的校驗(yàn)。詳細(xì)代碼

click事件觸發(fā)登錄操作:

this.$store.dispatch("LoginByUsername", this.loginForm).then(() => {
  this.$router.push({ path: "/" }); //登錄成功之后重定向到首頁(yè)
}).catch(err => {
  this.$message.error(err); //登錄失敗提示錯(cuò)誤
});

action:

LoginByUsername({ commit }, userInfo) {
  const username = userInfo.username.trim()
  return new Promise((resolve, reject) => {
    loginByUsername(username, userInfo.password).then(response => {
      const data = response.data
      Cookies.set("Token", response.data.token) //登錄成功后將token存儲(chǔ)在cookie之中
      commit("SET_TOKEN", data.token)
      resolve()
    }).catch(error => {
      reject(error)
    });
  });
}

登錄成功后,服務(wù)端會(huì)返回一個(gè) token(該token的是一個(gè)能唯一標(biāo)示用戶身份的一個(gè)key),之后我們將token存儲(chǔ)在本地cookie之中,這樣下次打開頁(yè)面或者刷新頁(yè)面的時(shí)候能記住用戶的登錄狀態(tài),不用再去登錄頁(yè)面重新登錄了。

ps:為了保證安全性,我司現(xiàn)在后臺(tái)所有token有效期(Expires/Max-Age)都是Session,就是當(dāng)瀏覽器關(guān)閉了就丟失了。重新打開游覽器都需要重新登錄驗(yàn)證,后端也會(huì)在每周固定一個(gè)時(shí)間點(diǎn)重新刷新token,讓后臺(tái)用戶全部重新登錄一次,確保后臺(tái)用戶不會(huì)因?yàn)殡娔X遺失或者其它原因被人隨意使用賬號(hào)。

獲取用戶信息

用戶登錄成功之后,我們會(huì)在全局鉤子router.beforeEach中攔截路由,判斷是否已獲得token,在獲得token之后我們就要去獲取用戶的基本信息了

//router.beforeEach
if (store.getters.roles.length === 0) { // 判斷當(dāng)前用戶是否已拉取完user_info信息
  store.dispatch("GetInfo").then(res => { // 拉取user_info
    const roles = res.data.role;
    next();//resolve 鉤子
  })

就如前面所說(shuō)的,我只在本地存儲(chǔ)了一個(gè)用戶的token,并沒(méi)有存儲(chǔ)別的用戶信息(如用戶權(quán)限,用戶名,用戶頭像等)。有些人會(huì)問(wèn)為什么不把一些其它的用戶信息也存一下?主要出于如下的考慮:

假設(shè)我把用戶權(quán)限和用戶名也存在了本地,但我這時(shí)候用另一臺(tái)電腦登錄修改了自己的用戶名,之后再用這臺(tái)存有之前用戶信息的電腦登錄,它默認(rèn)會(huì)去讀取本地 cookie 中的名字,并不會(huì)去拉去新的用戶信息。

所以現(xiàn)在的策略是:頁(yè)面會(huì)先從 cookie 中查看是否存有 token,沒(méi)有,就走一遍上一部分的流程重新登錄,如果有token,就會(huì)把這個(gè) token 返給后端去拉取user_info,保證用戶信息是最新的。
當(dāng)然如果是做了單點(diǎn)登錄得功能的話,用戶信息存儲(chǔ)在本地也是可以的。當(dāng)你一臺(tái)電腦登錄時(shí),另一臺(tái)會(huì)被提下線,所以總會(huì)重新登錄獲取最新的內(nèi)容。

而且從代碼層面我建議還是把 loginget_user_info兩件事分開比較好,在這個(gè)后端全面微服務(wù)的年代,后端同學(xué)也想寫優(yōu)雅的代碼~

權(quán)限篇

先說(shuō)一說(shuō)我權(quán)限控制的主體思路,前端會(huì)有一份路由表,它表示了每一個(gè)路由可訪問(wèn)的權(quán)限。當(dāng)用戶登錄之后,通過(guò) token 獲取用戶的 role ,動(dòng)態(tài)根據(jù)用戶的 role 算出其對(duì)應(yīng)有權(quán)限的路由,再通過(guò)router.addRoutes動(dòng)態(tài)掛載路由。但這些控制都只是頁(yè)面級(jí)的,說(shuō)白了前端再怎么做權(quán)限控制都不是絕對(duì)安全的,后端的權(quán)限驗(yàn)證是逃不掉的。

我司現(xiàn)在就是前端來(lái)控制頁(yè)面級(jí)的權(quán)限,不同權(quán)限的用戶顯示不同的側(cè)邊欄和限制其所能進(jìn)入的頁(yè)面(也做了少許按鈕級(jí)別的權(quán)限控制),后端則會(huì)驗(yàn)證每一個(gè)涉及請(qǐng)求的操作,驗(yàn)證其是否有該操作的權(quán)限,每一個(gè)后臺(tái)的請(qǐng)求不管是 get 還是 post 都會(huì)讓前端在請(qǐng)求 header里面攜帶用戶的 token,后端會(huì)根據(jù)該 token 來(lái)驗(yàn)證用戶是否有權(quán)限執(zhí)行該操作。若沒(méi)有權(quán)限則拋出一個(gè)對(duì)應(yīng)的狀態(tài)碼,前端檢測(cè)到該狀態(tài)碼,做出相對(duì)應(yīng)的操作。

權(quán)限 前端or后端 來(lái)控制?

有很多人表示他們公司的路由表是于后端根據(jù)用戶的權(quán)限動(dòng)態(tài)生成的,我司不采取這種方式的原因如下:

項(xiàng)目不斷的迭代你會(huì)異常痛苦,前端新開發(fā)一個(gè)頁(yè)面還要讓后端配一下路由和權(quán)限,讓我們想了曾經(jīng)前后端不分離,被后端支配的那段恐怖時(shí)間了。

其次,就拿我司的業(yè)務(wù)來(lái)說(shuō),雖然后端的確也是有權(quán)限驗(yàn)證的,但它的驗(yàn)證其實(shí)是針對(duì)業(yè)務(wù)來(lái)劃分的,比如超級(jí)編輯可以發(fā)布文章,而實(shí)習(xí)編輯只能編輯文章不能發(fā)布,但對(duì)于前端來(lái)說(shuō)不管是超級(jí)編輯還是實(shí)習(xí)編輯都是有權(quán)限進(jìn)入文章編輯頁(yè)面的。所以前端和后端權(quán)限的劃分是不太一致。

還有一點(diǎn)是就vue2.2.0之前異步掛載路由是很麻煩的一件事!不過(guò)好在官方也出了新的api,雖然本意是來(lái)解決ssr的痛點(diǎn)的。。。

addRoutes

在之前通過(guò)后端動(dòng)態(tài)返回前端路由一直很難做的,因?yàn)関ue-router必須是要vue在實(shí)例化之前就掛載上去的,不太方便動(dòng)態(tài)改變。不過(guò)好在vue2.2.0以后新增了router.addRoutes

Dynamically add more routes to the router. The argument must be an Array using the same route config format with the routes constructor option.

有了這個(gè)我們就可相對(duì)方便的做權(quán)限控制了。(樓主之前在權(quán)限控制也走了不少歪路,可以在項(xiàng)目的commit記錄中看到,重構(gòu)了很多次,最早沒(méi)用addRoute整個(gè)權(quán)限控制代碼里都是各種if/else的邏輯判斷,代碼相當(dāng)?shù)鸟詈虾蛷?fù)雜)

具體實(shí)現(xiàn)

創(chuàng)建vue實(shí)例的時(shí)候?qū)ue-router掛載,但這個(gè)時(shí)候vue-router掛載一些登錄或者不用權(quán)限的公用的頁(yè)面。

當(dāng)用戶登錄后,獲取用role,將role和路由表每個(gè)頁(yè)面的需要的權(quán)限作比較,生成最終用戶可訪問(wèn)的路由表。

調(diào)用router.addRoutes(store.getters.addRouters)添加用戶可訪問(wèn)的路由。

使用vuex管理路由表,根據(jù)vuex中可訪問(wèn)的路由渲染側(cè)邊欄組件。

router.js

首先我們實(shí)現(xiàn)router.js路由表,這里就拿前端控制路由來(lái)舉例(后端存儲(chǔ)的也差不多,稍微改造一下就好了)

// router.js
import Vue from "vue";
import Router from "vue-router";

import Login from "../views/login/";
const dashboard = resolve => require(["../views/dashboard/index"], resolve);
//使用了vue-routerd的[Lazy Loading Routes
](https://router.vuejs.org/en/advanced/lazy-loading.html)

//所有權(quán)限通用路由表 
//如首頁(yè)和登錄頁(yè)和一些不用權(quán)限的公用頁(yè)面
export const constantRouterMap = [
  { path: "/login", component: Login },
  {
    path: "/",
    component: Layout,
    redirect: "/dashboard",
    name: "首頁(yè)",
    children: [{ path: "dashboard", component: dashboard }]
  },
]

//實(shí)例化vue的時(shí)候只掛載constantRouter
export default new Router({
  routes: constantRouterMap
});

//異步掛載的路由
//動(dòng)態(tài)需要根據(jù)權(quán)限加載的路由表 
export const asyncRouterMap = [
  {
    path: "/permission",
    component: Layout,
    name: "權(quán)限測(cè)試",
    meta: { role: ["admin","super_editor"] }, //頁(yè)面需要的權(quán)限
    children: [
    { 
      path: "index",
      component: Permission,
      name: "權(quán)限測(cè)試頁(yè)",
      meta: { role: ["admin","super_editor"] }  //頁(yè)面需要的權(quán)限
    }]
  },
  { path: "*", redirect: "/404", hidden: true }
];

這里我們根據(jù) vue-router官方推薦 的方法通過(guò)meta標(biāo)簽來(lái)標(biāo)示改頁(yè)面能訪問(wèn)的權(quán)限有哪些。如meta: { role: ["admin","super_editor"] }表示該頁(yè)面只有admin和超級(jí)編輯才能有資格進(jìn)入。

注意事項(xiàng):這里有一個(gè)需要非常注意的地方就是 404 頁(yè)面一定要最后加載,如果放在constantRouterMap一同聲明了404,后面的所以頁(yè)面都會(huì)被攔截到404,詳細(xì)的問(wèn)題見(jiàn)addRoutes when you"ve got a wildcard route for 404s does not work

main.js

關(guān)鍵的main.js

// main.js
router.beforeEach((to, from, next) => {
  if (store.getters.token) { // 判斷是否有token
    if (to.path === "/login") {
      next({ path: "/" });
    } else {
      if (store.getters.roles.length === 0) { // 判斷當(dāng)前用戶是否已拉取完user_info信息
        store.dispatch("GetInfo").then(res => { // 拉取info
          const roles = res.data.role;
          store.dispatch("GenerateRoutes", { roles }).then(() => { // 生成可訪問(wèn)的路由表
            router.addRoutes(store.getters.addRouters) // 動(dòng)態(tài)添加可訪問(wèn)路由表
            next({ ...to, replace: true }) // hack方法 確保addRoutes已完成 ,set the replace: true so the navigation will not leave a history record
          })
        }).catch(err => {
          console.log(err);
        });
      } else {
        next() //當(dāng)有用戶權(quán)限的時(shí)候,說(shuō)明所有可訪問(wèn)路由已生成 如訪問(wèn)沒(méi)權(quán)限的全面會(huì)自動(dòng)進(jìn)入404頁(yè)面
      }
    }
  } else {
    if (whiteList.indexOf(to.path) !== -1) { // 在免登錄白名單,直接進(jìn)入
      next();
    } else {
      next("/login"); // 否則全部重定向到登錄頁(yè)
    }
  }
});

這里的router.beforeEach也結(jié)合了上一章講的一些登錄邏輯代碼。


上面一張圖就是在使用addRoutes方法之前的權(quán)限判斷,非常的繁瑣,因?yàn)槲沂前阉械穆酚啥紥煸诹松先?,所有我要各種判斷當(dāng)前的用戶是否有權(quán)限進(jìn)入該頁(yè)面,各種if/else的嵌套,維護(hù)起來(lái)相當(dāng)?shù)睦щy。但現(xiàn)在有了addRoutes之后就非常的方便,我只掛載了用戶有權(quán)限進(jìn)入的頁(yè)面,沒(méi)權(quán)限,路由自動(dòng)幫我跳轉(zhuǎn)的404,省去了不少的判斷。

這里還有一個(gè)小hack的地方,就是router.addRoutes之后的next()可能會(huì)失效,因?yàn)榭赡?b>next()的時(shí)候路由并沒(méi)有完全add完成,好在查閱文檔發(fā)現(xiàn)

next("/") or next({ path: "/" }): redirect to a different location. The current navigation will be aborted and a new one will be started.

這樣我們就可以簡(jiǎn)單的通過(guò)next(to)巧妙的避開之前的那個(gè)問(wèn)題了。這行代碼重新進(jìn)入router.beforeEach這個(gè)鉤子,這時(shí)候再通過(guò)next()來(lái)釋放鉤子,就能確保所有的路由都已經(jīng)掛在完成了。

store/permission.js

就來(lái)就講一講 GenerateRoutes Action

// store/permission.js
import { asyncRouterMap, constantRouterMap } from "src/router";

function hasPermission(roles, route) {
  if (route.meta && route.meta.role) {
    return roles.some(role => route.meta.role.indexOf(role) >= 0)
  } else {
    return true
  }
}

const permission = {
  state: {
    routers: constantRouterMap,
    addRouters: []
  },
  mutations: {
    SET_ROUTERS: (state, routers) => {
      state.addRouters = routers;
      state.routers = constantRouterMap.concat(routers);
    }
  },
  actions: {
    GenerateRoutes({ commit }, data) {
      return new Promise(resolve => {
        const { roles } = data;
        const accessedRouters = asyncRouterMap.filter(v => {
          if (roles.indexOf("admin") >= 0) return true;
          if (hasPermission(roles, v)) {
            if (v.children && v.children.length > 0) {
              v.children = v.children.filter(child => {
                if (hasPermission(roles, child)) {
                  return child
                }
                return false;
              });
              return v
            } else {
              return v
            }
          }
          return false;
        });
        commit("SET_ROUTERS", accessedRouters);
        resolve();
      })
    }
  }
};

export default permission;

這里的代碼說(shuō)白了就是干了一件事,通過(guò)用戶的權(quán)限和之前在router.js里面asyncRouterMap的每一個(gè)頁(yè)面所需要的權(quán)限做匹配,最后返回一個(gè)該用戶能夠訪問(wèn)路由有哪些。

側(cè)邊欄

最后一個(gè)涉及到權(quán)限的地方就是側(cè)邊欄,不過(guò)在前面的基礎(chǔ)上已經(jīng)很方便就能實(shí)現(xiàn)動(dòng)態(tài)顯示側(cè)邊欄了。這里側(cè)邊欄基于element-ui的NavMenu來(lái)實(shí)現(xiàn)的。
代碼有點(diǎn)多不貼詳細(xì)的代碼了,有興趣的可以直接去github上看地址,或者直接看關(guān)于側(cè)邊欄的文檔。

說(shuō)白了就是遍歷之前算出來(lái)的permission_routers,通過(guò)vuex拿到之后動(dòng)態(tài)v-for渲染而已。不過(guò)這里因?yàn)橛幸恍I(yè)務(wù)需求所以加了很多判斷
比如我們?cè)诙x路由的時(shí)候會(huì)加很多參數(shù)

/**
* hidden: true                   if `hidden:true` will not show in the sidebar(default is false)
* redirect: noredirect           if `redirect:noredirect` will no redirct in the breadcrumb
* name:"router-name"             the name is used by  (must set!!!)
* meta : {
   role: ["admin","editor"]     will control the page role (you can set multiple roles)
   title: "title"               the name show in submenu and breadcrumb (recommend set)
   icon: "svg-name"             the icon show in the sidebar,
   noCache: true                if fasle ,the page will no be cached(default is false)
 }
**/

這里僅供參考,而且本項(xiàng)目為了支持無(wú)限嵌套路由,所有側(cè)邊欄這塊使用了遞歸組件。如需要請(qǐng)大家自行改造,來(lái)打造滿足自己業(yè)務(wù)需求的側(cè)邊欄。

側(cè)邊欄高亮問(wèn)題:很多人在群里問(wèn)為什么自己的側(cè)邊欄不能跟著自己的路由高亮,其實(shí)很簡(jiǎn)單,element-ui官方已經(jīng)給了default-active所以我們只要

:default-active="$route.path"
default-active一直指向當(dāng)前路由就可以了,就是這么簡(jiǎn)單
按鈕級(jí)別權(quán)限控制

有很多人一直在問(wèn)關(guān)于按鈕級(jí)別粒度的權(quán)限控制怎么做。我司現(xiàn)在是這樣的,真正需要按鈕級(jí)別控制的地方不是很多,現(xiàn)在是通過(guò)獲取到用戶的role之后,在前端用v-if手動(dòng)判斷來(lái)區(qū)分不同權(quán)限對(duì)應(yīng)的按鈕的。理由前面也說(shuō)了,我司顆粒度的權(quán)限判斷是交給后端來(lái)做的,每個(gè)操作后端都會(huì)進(jìn)行權(quán)限判斷。而且我覺(jué)得其實(shí)前端真正需要按鈕級(jí)別判斷的地方不是很多,如果一個(gè)頁(yè)面有很多種不同權(quán)限的按鈕,我覺(jué)得更多的應(yīng)該是考慮產(chǎn)品層面是否設(shè)計(jì)合理。當(dāng)然你強(qiáng)行說(shuō)我想做按鈕級(jí)別的權(quán)限控制,你也可以參照路由層面的做法,搞一個(gè)操作權(quán)限表。。。但個(gè)人覺(jué)得有點(diǎn)多此一舉。或者將它封裝成一個(gè)指令都是可以的。

axios攔截器

這里再說(shuō)一說(shuō) axios 吧。雖然在上一篇系列文章中簡(jiǎn)單介紹過(guò),不過(guò)這里還是要在嘮叨一下。如上文所說(shuō),我司服務(wù)端對(duì)每一個(gè)請(qǐng)求都會(huì)驗(yàn)證權(quán)限,所以這里我們針對(duì)業(yè)務(wù)封裝了一下請(qǐng)求。首先我們通過(guò)request攔截器在每個(gè)請(qǐng)求頭里面塞入token,好讓后端對(duì)請(qǐng)求進(jìn)行權(quán)限驗(yàn)證。并創(chuàng)建一個(gè)respone攔截器,當(dāng)服務(wù)端返回特殊的狀態(tài)碼,我們統(tǒng)一做處理,如沒(méi)權(quán)限或者token失效等操作。

import axios from "axios"
import { Message } from "element-ui"
import store from "@/store"
import { getToken } from "@/utils/auth"

// 創(chuàng)建axios實(shí)例
const service = axios.create({
  baseURL: process.env.BASE_API, // api的base_url
  timeout: 5000 // 請(qǐng)求超時(shí)時(shí)間
})

// request攔截器
service.interceptors.request.use(config => {
  // Do something before request is sent
  if (store.getters.token) {
    config.headers["X-Token"] = getToken() // 讓每個(gè)請(qǐng)求攜帶token--["X-Token"]為自定義key 請(qǐng)根據(jù)實(shí)際情況自行修改
  }
  return config
}, error => {
  // Do something with request error
  console.log(error) // for debug
  Promise.reject(error)
})

// respone攔截器
service.interceptors.response.use(
  response => response,
  /**
  * 下面的注釋為通過(guò)response自定義code來(lái)標(biāo)示請(qǐng)求狀態(tài),當(dāng)code返回如下情況為權(quán)限有問(wèn)題,登出并返回到登錄頁(yè)
  * 如通過(guò)xmlhttprequest 狀態(tài)碼標(biāo)識(shí) 邏輯可寫在下面error中
  */
  //  const res = response.data;
  //     if (res.code !== 20000) {
  //       Message({
  //         message: res.message,
  //         type: "error",
  //         duration: 5 * 1000
  //       });
  //       // 50008:非法的token; 50012:其他客戶端登錄了;  50014:Token 過(guò)期了;
  //       if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
  //         MessageBox.confirm("你已被登出,可以取消繼續(xù)留在該頁(yè)面,或者重新登錄", "確定登出", {
  //           confirmButtonText: "重新登錄",
  //           cancelButtonText: "取消",
  //           type: "warning"
  //         }).then(() => {
  //           store.dispatch("FedLogOut").then(() => {
  //             location.reload();// 為了重新實(shí)例化vue-router對(duì)象 避免bug
  //           });
  //         })
  //       }
  //       return Promise.reject("error");
  //     } else {
  //       return response.data;
  //     }
  error => {
    console.log("err" + error)// for debug
    Message({
      message: error.message,
      type: "error",
      duration: 5 * 1000
    })
    return Promise.reject(error)
  })

export default service
兩步驗(yàn)證

文章一開始也說(shuō)了,后臺(tái)的安全性是很重要的,簡(jiǎn)簡(jiǎn)單單的一個(gè)賬號(hào)+密碼的方式是很難保證安全性的。所以我司的后臺(tái)項(xiàng)目都是用了兩步驗(yàn)證的方式,之前我們也嘗試過(guò)使用基于 google-authenticator 或者youbikey這樣的方式但難度和操作成本都比較大。后來(lái)還是準(zhǔn)備借助騰訊爸爸,這年代誰(shuí)不用微信。。。安全性騰訊爸爸也幫我做好了保障。
樓主建議兩步驗(yàn)證要支持多個(gè)渠道不要只微信或者QQ,前段時(shí)間QQ第三方登錄就出了bug,官方兩三天才修好的,害我背了鍋/(ㄒoㄒ)/~~ 。

這里的兩部驗(yàn)證有點(diǎn)名不副實(shí),其實(shí)就是賬號(hào)密碼驗(yàn)證過(guò)之后還需要一個(gè)綁定的第三方平臺(tái)登錄驗(yàn)證而已。
寫起來(lái)也很簡(jiǎn)單,在原有登錄得邏輯上改造一下就好。

this.$store.dispatch("LoginByEmail", this.loginForm).then(() => {
  //this.$router.push({ path: "/" });
  //不重定向到首頁(yè)
  this.showDialog = true //彈出選擇第三方平臺(tái)的dialog
}).catch(err => {
  this.$message.error(err); //登錄失敗提示錯(cuò)誤
});

登錄成功之后不直接跳到首頁(yè)而是讓用戶兩步登錄,選擇登錄得平臺(tái)。
接下來(lái)就是所有第三方登錄一樣的地方通過(guò) OAuth2.0 授權(quán)。這個(gè)各大平臺(tái)大同小異,大家自行查閱文檔,不展開了,就說(shuō)一個(gè)微信授權(quán)比較坑的地方。注意你連參數(shù)的順序都不能換,不然會(huì)驗(yàn)證不通過(guò)。具體代碼,同時(shí)我也封裝了openWindow方法大家自行看吧。
當(dāng)?shù)谌绞跈?quán)成功之后都會(huì)跳到一個(gè)你之前有一個(gè)傳入redirect——uri的頁(yè)面

如微信還必須是你授權(quán)賬號(hào)的一級(jí)域名。所以你授權(quán)的域名是vue-element-admin.com,你就必須重定向到vue-element-admin.com/xxx/下面,所以你需要寫一個(gè)重定向的服務(wù),如vue-element-admin.com/auth/redirect?a.com 跳到該頁(yè)面時(shí)會(huì)再次重定向給a.com。

所以我們后臺(tái)也需要開一個(gè)authredirect頁(yè)面:代碼。他的作用是第三方登錄成功之后會(huì)默認(rèn)跳到授權(quán)的頁(yè)面,授權(quán)的頁(yè)面會(huì)再次重定向回我們的后臺(tái),由于是spa,改變路由的體驗(yàn)不好,我們通過(guò)window.opener.location.href的方式改變hash,在login.js里面再監(jiān)聽(tīng)hash的變化。當(dāng)hash變化時(shí),獲取之前第三方登錄成功返回的code與第一步賬號(hào)密碼登錄之后返回的uid一同發(fā)送給服務(wù)端驗(yàn)證是否正確,如果正確,這時(shí)候就是真正的登錄成功。

 created() {
     window.addEventListener("hashchange", this.afterQRScan);
   },
   destroyed() {
     window.removeEventListener("hashchange", this.afterQRScan);
   },
   afterQRScan() {
     const hash = window.location.hash.slice(1);
     const hashObj = getQueryObject(hash);
     const originUrl = window.location.origin;
     history.replaceState({}, "", originUrl);
     const codeMap = {
       wechat: "code",
       tencent: "code"
     };
     const codeName = hashObj[codeMap[this.auth_type]];
     this.$store.dispatch("LoginByThirdparty", codeName).then(() => {
       this.$router.push({
         path: "/"
       });
     });
   }

到這里涉及登錄權(quán)限的東西也差不多講完了,這里樓主只是給了大家一個(gè)實(shí)現(xiàn)的思路(都是樓主不斷摸索的血淚史),每個(gè)公司實(shí)現(xiàn)的方案都有些出入,請(qǐng)謹(jǐn)慎選擇適合自己業(yè)務(wù)形態(tài)的解決方案。如果有什么想法或者建議歡迎去本項(xiàng)目下留言,一同討論。

占坑

常規(guī)占坑,這里是手摸手,帶你用vue擼后臺(tái)系列。
完整項(xiàng)目地址:vue-element-admin
系類文章一:手摸手,帶你用vue擼后臺(tái) 系列一(基礎(chǔ)篇)
系類文章二:手摸手,帶你用vue擼后臺(tái) 系列二(登錄權(quán)限篇)
系類文章三:手摸手,帶你用vue 擼后臺(tái) 系列三 (實(shí)戰(zhàn)篇)
系類文章四:手摸手,帶你用vue擼后臺(tái) 系列四(vueAdmin 一個(gè)極簡(jiǎn)的后臺(tái)基礎(chǔ)模板)
系類文章:手摸手,帶你優(yōu)雅的使用 icon
系類文章:手摸手,帶你封裝一個(gè)vue component
樓主個(gè)人免費(fèi)圈子

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/83139.html

相關(guān)文章

  • 摸手,帶你封裝一個(gè)vue component

    摘要:靈活性和針對(duì)性。所以我覺(jué)得大部分組件還是自己封裝來(lái)的更為方便和靈活一些。動(dòng)手開干接下來(lái)我們一起手摸手教改造包裝一個(gè)插件,只要幾分鐘就可以封裝一個(gè)專屬于你的。 項(xiàng)目地址:vue-countTo配套完整后臺(tái)demo地址:vue-element-admin系類文章一:手摸手,帶你用vue擼后臺(tái) 系列一(基礎(chǔ)篇)系類文章二:手摸手,帶你用vue擼后臺(tái) 系列二(登錄權(quán)限篇)系類文章三:手摸手,帶...

    pkhope 評(píng)論0 收藏0
  • 摸手,你用vue后臺(tái) 系列一(基礎(chǔ))

    摘要:詳細(xì)具體的使用可以見(jiàn)文章手摸手,帶你優(yōu)雅的使用。為了加速線上鏡像構(gòu)建的速度,我們利用源進(jìn)行加速并且將一些常見(jiàn)的依賴打入了基礎(chǔ)鏡像,避免每次都需要重新下載。 完整項(xiàng)目地址:vue-element-admin系類文章二:手摸手,帶你用vue擼后臺(tái) 系列二(登錄權(quán)限篇)系類文章三:手摸手,帶你用vue擼后臺(tái) 系列三(實(shí)戰(zhàn)篇)系類文章四:手摸手,帶你用vue擼后臺(tái) 系列四(vueAdmin 一...

    xiaotianyi 評(píng)論0 收藏0
  • vue2+element 管理后臺(tái) 集成解決方案 沒(méi)有沒(méi)做的,只要想不到的!

    摘要:目前的技術(shù)棧主要的采用由于是個(gè)人項(xiàng)目,所以數(shù)據(jù)請(qǐng)求都是用了代替。后續(xù)會(huì)出一系列的教程配套文章,如如何從零構(gòu)建后臺(tái)項(xiàng)目框架,如何做完整的用戶系統(tǒng)如權(quán)限驗(yàn)證,二次登錄等,如何二次開發(fā)組件如富文本,如何整合七牛等等文章,各種后臺(tái)開發(fā)經(jīng)驗(yàn)等等。 完整項(xiàng)目地址:vue-element-admin系類文章一:手摸手,帶你用vue擼后臺(tái) 系列一(基礎(chǔ)篇)系類文章二:手摸手,帶你用vue擼后臺(tái) 系列二...

    sanyang 評(píng)論0 收藏0
  • 摸手,你用vue后臺(tái) 系列三(實(shí)戰(zhàn))

    摘要:社區(qū)的認(rèn)可目前已經(jīng)是相關(guān)最多的開源項(xiàng)目了,體現(xiàn)出了社區(qū)對(duì)其的認(rèn)可。監(jiān)聽(tīng)事件手動(dòng)維護(hù)列表這樣我們就簡(jiǎn)單的完成了拖拽排序。 完整項(xiàng)目地址:vue-element-admin 系類文章一:手摸手,帶你用vue擼后臺(tái) 系列一(基礎(chǔ)篇)系類文章二:手摸手,帶你用vue擼后臺(tái) 系列二(登錄權(quán)限篇)系類文章三:手摸手,帶你用vue擼后臺(tái) 系列三(實(shí)戰(zhàn)篇)系類文章四:手摸手,帶你用vue擼后臺(tái) 系列...

    Channe 評(píng)論0 收藏0
  • 摸手,你用vue后臺(tái) 系列三(實(shí)戰(zhàn))

    摘要:社區(qū)的認(rèn)可目前已經(jīng)是相關(guān)最多的開源項(xiàng)目了,體現(xiàn)出了社區(qū)對(duì)其的認(rèn)可。監(jiān)聽(tīng)事件手動(dòng)維護(hù)列表這樣我們就簡(jiǎn)單的完成了拖拽排序。 完整項(xiàng)目地址:vue-element-admin 系類文章一:手摸手,帶你用vue擼后臺(tái) 系列一(基礎(chǔ)篇)系類文章二:手摸手,帶你用vue擼后臺(tái) 系列二(登錄權(quán)限篇)系類文章三:手摸手,帶你用vue擼后臺(tái) 系列三(實(shí)戰(zhàn)篇)系類文章四:手摸手,帶你用vue擼后臺(tái) 系列...

    zgbgx 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<