緣起
哈嘍大家好,今天周四啦,樓主明天要正式放假了,這里先祝大家節日快樂咯,希望在家里能繼續研究點兒東西吧,今天呢是 nuxt 的最后一篇,主要是對權限登錄進行研究,這一塊咱們之前在說第一個項目的時候已經稍微說到了,具體的邏輯大家可以查看這篇文章《二十四║ Vuex + JWT 實現授權驗證登錄》,具體的運行原理和流程,以及什么是 vuex ,在那里已經說的很清楚了,今天咱們就是主要在 nuxt 框架中使用,主要的代碼的形式,理論知識比較少了,大家可以歇一歇了。這幾天寫了這么多,好多人可能都沒看,不過沒關系,繼續回顧:
《二七║ Nuxt 基礎:框架初探》:通過 SSR 來引入 nuxt 框架,第一次接觸到該框架;
《二八║ Nuxt 基礎:面向源碼研究Nuxt.js》:通過研究 node_modules 中的源碼,帶領大家一步步了解 nuxt 是如何進行服務端渲染的;
《二九║ Nuxt實戰:異步實現數據雙端渲染》:通過首頁的數據加載,更加深刻的了解到 nuxt 的雙端渲染,異步很重要;
《 三十║ Nuxt實戰:動態路由+同構》:通過首頁和詳情頁的交互,進一步鞏固 nuxt 的渲染模式和動態路由效果。
從上邊大家可以看到,幾乎每一篇都會說到 nuxt 這個框架的渲染模式,這個很重要,更是對 vue 的鞏固。好啦,馬上開始今天的講解~
零、今天要完成橙色的部分
一、為詳情頁增加權限驗證
今天呢,咱們換一種玩兒法,就是將我們的詳情頁給增加一個權限,首頁的數據大家都可以隨便看,但是詳情頁卻不能隨便看,必須要登錄,那我們就需要在我們的詳情頁增加一個權限,
如果 token 存在,則發送請求驗證,如果不存在,直接跳轉到登錄頁,那我們首先要添加一個登錄頁
1、添加登錄頁,獲取token
在 pages頁面文件夾下,新建login 文件夾,然后添加 index.vue 登錄頁面,
這一塊邏輯和我們之前的很像,大家可以參考着做對比
<template> <el-row type="flex" justify="center"> <el-card v-if="isLogin"> 歡迎:admins <br> <br> <el-button type="primary" icon="el-icon-upload" @click="loginOut">退出登錄</el-button> </el-card> <el-form v-else ref="loginForm" :model="user" :rules="rules" status-icon label-width="50px"> <el-form-item label="賬號" prop="name"> <el-input v-model="user.name"></el-input> </el-form-item> <el-form-item label="密碼" prop="pass"> <el-input v-model="user.pass" type="password"></el-input> </el-form-item> <el-form-item> <el-button type="primary" icon="el-icon-upload" @click="login">登錄</el-button> </el-form-item> </el-form> </el-row> </template> <script> import Vue from "vue"; export default { methods: { login: function() { let that = this; that.$store.commit("saveToken", ""); this.$refs.loginForm.validate(valid => { if (valid) { //發送請求登錄,這里要注意下返回數據格式,如果有問題,參考 http.js 中的 response 設置 Vue.http.get("Login/GetTokenNuxt?name="+that.user.name+"&pass="+that.user.name+"").then(res => { if (res.success) { console.log("登錄成功"); var token = res.token; that.$store.commit("saveToken", token); this.$notify({ type: "success", message: "歡迎你," + this.user.name + "!", duration: 3000 }); this.$router.replace("/"); } }).catch(err => { console.log("點贊失敗", err); }); } else { return false; } }); }, loginOut(){ this.isLogin=false; this.$store.commit("saveToken", ""); } }, data() { return { isLogin:false, user: {}, rules: { name: [{ required: true, message: "用戶名不能為空", trigger: "blur" }], pass: [{ required: true, message: "密碼不能為空", trigger: "blur" }] } }; }, created() { } } </script>
2、自定義服務端插件 elementUI
提醒:這里我用到了 elementUI ,請安裝
npm i element-ui -S
安裝成功后,作為插件使用,如果你不是很了解,請訪問官網《插 件》一章節,這里說的很清楚,我在之前的文件中也有提到。
在 plugins/server_site 文件夾下,新增 ElementUI.js 文件,作為我們的插件
import Vue from 'vue' import ElementUI from 'element-ui' Vue.use(ElementUI)
然后把這個 js 插件導入到 index.js 中,和 http.js一起注入到nuxt.config.js 中
//這個是 server_site 服務端插件全部 import Vue from "vue"; import http from "./http.js"; import "./ElementUI.js";//導入 elementUI插件 const install = function (VueClass, opts = {}) { // http method VueClass.http = http; VueClass.prototype.$http = http; }; Vue.use(install);
因為我們是把服務端的插件都打包了 server_site 下的index中,所以我們以后不用每一個都注入到我們的配置文件 nuxt.config.js 中,只需要將 服務端插件 一個放進去即可,但是樣式還是需要引用的
3、在 strore 文件夾中,添加 index.js 文件,設置我們的store數據
import Vue from "vue"; import Vuex from "vuex"; Vue.use(Vuex); const store = () => new Vuex.Store({ state: { isLogined: false, token: "",//這里主要是用到了 token userInfo: { name: "" }, loginBoxVisible: false }, mutations: { //保存 token 到 store和本地中 saveToken(state, data) { state.token = data; window.localStorage.setItem("Token", data); }, changeLoginState (state, isLogined) { state.isLogined = isLogined; }, changeLoginBoxVisible (state, visible) { state.loginBoxVisible = visible; }, updateUserInfo (state, userInfo) { state.userInfo = userInfo; } }, actions: { initUser ({ state, commit }) { const user = JSON.parse(localStorage.getItem("userInfo")); if (user) { state.userInfo = user; commit("changeLoginState", true); } } } }); export default store;
4、詳情頁中增加權限驗證
大家一定還記得這個圖片,這個是我們之前講到的 nuxt 的執行流程圖,這里說下 fetch()
fetch 方法用於在渲染頁面前填充應用的狀態樹(store)數據, 與 asyncData 方法類似,不同的是它不會設置組件的數據。
如果頁面組件設置了
fetch
方法,它會在組件每次加載前被調用(在服務端或切換至目標路由之前)。
我們可以利用該方法,獲取 狀態樹 中的 token 信息,並做處理,在昨天的基礎上,我們只對 fetch() 方法,簡單修改
<script> import Vue from "vue"; export default { layout: "blog", async asyncData ({ params, error }) { // 獲取文章詳情 let data = {}; try { data = await Vue.http.get(`blog/${params.id}`); return { data: data }; } catch (e) { //error({ statusCode: 404, message: "出錯啦" }); } }, //在這里進行判斷 token fetch ({ store, redirect }) { if (!(store.state.token&&store.state.token.length>=128)) { //跳轉登錄頁 return redirect('/login') } }, data () { return { comments: [] }; }, head () { return { title: `${this.data.btitle}`, meta: [ { name: "description", content: this.data.btitle } ] }; } }; </script>
5、最后在 http.js 中,開啟 http 攔截器
// http.interceptors.request.use((data, headers) => { // return data; // }); //http request 攔截器 http.interceptors.request.use( config => { //注意,首次服務端渲染的時候,還沒有出現 DOM,所以找不到 windows 對象,這里用 try 處理掉了 try { if (window.localStorage.Token&&window.localStorage.Token.length>=128) {//store.state.token 獲取不到值 config.headers.Authorization = window.localStorage.Token; } }catch (e) { } return config; }, err => { return Promise.reject(err); } );
6、查看頁面,體驗效果
這里我們就已經限制了詳情頁,需要登錄才能查看,其實這一塊邏輯我們可以單拿出來放到中間件 middleware 里來使用,效果會更好,這里舉個栗子:路由鑒權
提醒: 因為我們用的是 store 判斷的是否登錄,但是如果刷新頁面,我們用的是 服務端渲染,所以 store 會被更新掉,也就是為空了,大家可以用兩個辦法處理
1、用 localStorage 來判斷是否存在token;2、每次服務端渲染,需要更新狀態樹 store 中的 token;
二、結語
今天的講解比較簡單,主要是驗證邏輯我們之前也已經提到了,在我們系列的 24 篇中,本文只是簡單的將其搬到我們的 nuxt 框架中來,只不過中間還是會有一些小問題大家需要注意:
1、插件 plugins 的使用很重要,2、基於 axios 的 http 封裝,我只是寫了簡單的一個 demo,復雜的大家可以找一些大的項目框架,自行研究研究;3、路由機制也是需要留心的一個小知識點,雖然不需要我們配置了,不過還是要了解內部結構。
好啦,nuxt 基本教程這里就說這么多吧,祝大家在大長假里開開森森噠~