การตรวจสอบสิทธิ์ใน Vue.js
เผยแพร่แล้ว: 2022-03-10การรับรองความถูกต้องเป็นคุณลักษณะที่จำเป็นสำหรับแอปพลิเคชันที่จัดเก็บข้อมูลผู้ใช้ เป็นกระบวนการในการยืนยันตัวตนของผู้ใช้ เพื่อให้มั่นใจว่าผู้ใช้ที่ไม่ได้รับอนุญาตจะไม่สามารถเข้าถึงข้อมูลส่วนตัวได้ — ข้อมูลที่เป็นของผู้ใช้รายอื่น สิ่งนี้นำไปสู่การมีเส้นทางที่จำกัดซึ่งสามารถเข้าถึงได้โดยผู้ใช้ที่ได้รับการรับรองความถูกต้องเท่านั้น ผู้ใช้ที่ผ่านการตรวจสอบสิทธิ์เหล่านี้จะได้รับการตรวจสอบโดยใช้รายละเอียดการเข้าสู่ระบบ (เช่น ชื่อผู้ใช้/อีเมล และรหัสผ่าน) และกำหนดโทเค็นเพื่อใช้ในการเข้าถึงทรัพยากรที่มีการป้องกันของแอปพลิเคชัน
ในบทความนี้ คุณจะได้เรียนรู้เกี่ยวกับ:
- การกำหนดค่า Vuex ด้วย Axios
- การกำหนดเส้นทาง
- การจัดการผู้ใช้
- การจัดการโทเค็นที่หมดอายุ
การพึ่งพา
เราจะทำงานกับการพึ่งพาต่อไปนี้ซึ่งช่วยในการรับรองความถูกต้อง:
- Axios
สำหรับการส่งและดึงข้อมูลจาก API . ของเรา - Vuex
สำหรับการจัดเก็บข้อมูลที่ได้รับจาก API . ของเรา - Vue-เราเตอร์
สำหรับการนำทางและการป้องกันเส้นทาง
เราจะทำงานร่วมกับเครื่องมือเหล่านี้และดูว่าจะทำงานร่วมกันได้อย่างไรเพื่อมอบฟังก์ชันการตรวจสอบสิทธิ์ที่มีประสิทธิภาพสำหรับแอปของเรา
แบ็กเอนด์ API
เราจะสร้างบล็อกไซต์อย่างง่าย ซึ่งจะใช้ประโยชน์จาก API นี้ คุณสามารถตรวจสอบเอกสารเพื่อดูปลายทางและวิธีส่งคำขอ
จากเอกสาร คุณจะสังเกตเห็นจุดปลายบางจุดที่แนบมาพร้อมกับล็อค นี่เป็นวิธีแสดงว่ามีเพียงผู้ใช้ที่ได้รับอนุญาตเท่านั้นที่สามารถส่งคำขอไปยังปลายทางเหล่านั้นได้ จุดสิ้นสุดที่ไม่จำกัดคือจุดปลาย /register
และ /login
ข้อผิดพลาดที่มีรหัสสถานะ 401
ควรถูกส่งกลับเมื่อผู้ใช้ที่ไม่ผ่านการตรวจสอบสิทธิ์พยายามเข้าถึงปลายทางที่ถูกจำกัด
หลังจากเข้าสู่ระบบผู้ใช้สำเร็จแล้ว โทเค็นการเข้าถึงพร้อมกับข้อมูลบางส่วนจะได้รับในแอป Vue ซึ่งจะใช้ในการตั้งค่าคุกกี้และแนบในส่วนหัวของคำขอเพื่อใช้สำหรับคำขอในอนาคต แบ็กเอนด์จะตรวจสอบส่วนหัวของคำขอทุกครั้งที่ส่งคำขอไปยังปลายทางที่ถูกจำกัด อย่าพยายามเก็บโทเค็นการเข้าถึงไว้ในที่จัดเก็บในเครื่อง

โครงการนั่งร้าน
ใช้ Vue CLI รันคำสั่งด้านล่างเพื่อสร้างแอปพลิเคชัน:
vue create auth-project
ไปที่โฟลเดอร์ใหม่ของคุณ:
cd auth-project
เพิ่ม vue-router และติดตั้งการพึ่งพาเพิ่มเติม — vuex และ axios:
vue add router npm install vuex axios
ตอนนี้เรียกใช้โครงการของคุณและคุณจะเห็นสิ่งที่ฉันมีด้านล่างบนเบราว์เซอร์ของคุณ:
npm run serve
1. การกำหนดค่า Vuex ด้วย Axios
Axios เป็นไลบรารี JavaScript ที่ใช้ในการส่งคำขอจากเบราว์เซอร์ไปยัง API ตามเอกสาร Vuex;
“Vuex เป็น รูปแบบการจัดการสถานะ + ไลบรารี สำหรับแอปพลิเคชัน Vue.js มันทำหน้าที่เป็นร้านค้าส่วนกลางสำหรับส่วนประกอบทั้งหมดในแอปพลิเคชัน โดยมีกฎที่ทำให้มั่นใจได้ว่าสถานะสามารถกลายพันธุ์ได้เฉพาะในรูปแบบที่คาดการณ์ได้เท่านั้น”
นั่นหมายความว่าอย่างไร? Vuex เป็นร้านค้าที่ใช้ในแอปพลิเคชั่น Vue ที่ช่วยให้เราสามารถ บันทึก ข้อมูลที่จะใช้ได้กับทุกองค์ประกอบและให้วิธีการเปลี่ยนข้อมูลดังกล่าว เราจะใช้ Axios ใน Vuex เพื่อส่งคำขอของเราและทำการเปลี่ยนแปลงสถานะของเรา (ข้อมูล) Axios จะถูกใช้ใน actions
Vuex เพื่อส่ง GET
และ POST
การตอบสนองที่ได้รับจะถูกใช้ในการส่งข้อมูลไปยังการ mutations
และอัปเดตข้อมูลร้านค้าของเรา
เพื่อจัดการกับการรีเซ็ต Vuex หลังจากรีเฟรช เราจะทำงานกับ vuex-persistedstate
ซึ่งเป็นไลบรารีที่บันทึกข้อมูล Vuex ของเราระหว่างการโหลดหน้าซ้ำ
npm install --save vuex-persistedstate
ตอนนี้เรามาสร้างโฟลเดอร์ที่ store
ใหม่ใน src
เพื่อกำหนดค่าร้าน Vuex ในโฟลเดอร์ store
ให้สร้างโฟลเดอร์ใหม่ modules
และไฟล์ index.js
สิ่งสำคัญที่ควรทราบคือ คุณต้องทำเช่นนี้ก็ต่อเมื่อโฟลเดอร์นี้ไม่ได้สร้างให้คุณโดยอัตโนมัติ
import Vuex from 'vuex'; import Vue from 'vue'; import createPersistedState from "vuex-persistedstate"; import auth from './modules/auth'; // Load Vuex Vue.use(Vuex); // Create store export default new Vuex.Store({ modules: { auth }, plugins: [createPersistedState()] });
ที่นี่เรากำลังใช้ Vuex
และนำเข้า module
การตรวจสอบสิทธิ์จากโฟลเดอร์ modules
ไปยังร้านค้าของเรา
โมดูล
โมดูลเป็นส่วนต่างๆ ของร้านค้าของเราที่จัดการงานที่คล้ายคลึงกัน ซึ่งรวมถึง:
- สถานะ
- การกระทำ
- การกลายพันธุ์
- getters
ก่อนที่เราจะดำเนินการแก้ไขไฟล์ main.js
ของเรา
import Vue from 'vue' import App from './App.vue' import router from './router'; import store from './store'; import axios from 'axios'; axios.defaults.withCredentials = true axios.defaults.baseURL = 'https://gabbyblog.herokuapp.com/'; Vue.config.productionTip = false new Vue({ store, router, render: h => h(App) }).$mount('#app')
เรานำเข้าวัตถุ store
จากโฟลเดอร์ ./store
รวมถึงแพ็คเกจ Axios
ดังที่กล่าวไว้ก่อนหน้านี้ คุกกี้โทเค็นการเข้าถึงและข้อมูลที่จำเป็นอื่นๆ ที่ได้รับจาก API จะต้องได้รับการตั้งค่าในส่วนหัวของคำขอสำหรับคำขอในอนาคต เนื่องจากเราจะใช้ Axios ในการส่งคำขอ เราจึงต้องกำหนดค่า Axios เพื่อใช้ประโยชน์จากสิ่งนี้ ในตัวอย่างด้านบน เราทำโดยใช้ axios.defaults.withCredentials = true
ซึ่งจำเป็นเพราะ Axios จะไม่ส่งคุกกี้ตามค่าเริ่มต้น
aaxios.defaults.withCredentials = true
เป็นคำสั่งให้ Axios ส่งคำขอทั้งหมดที่มีข้อมูลประจำตัวเช่น; ส่วนหัวการอนุญาต ใบรับรองไคลเอ็นต์ TLS หรือคุกกี้ (เช่นในกรณีของเรา)
เราตั้งค่า axios.defaults.baseURL
สำหรับคำขอ Axios ของเราเป็น API
ด้วยวิธีนี้ ทุกครั้งที่เราส่งผ่าน Axios จะใช้ URL พื้นฐานนี้ ด้วยเหตุนี้ เราจึงสามารถเพิ่มปลายทางของเราได้ เช่น /register
และ /login
ไปยังการกระทำของเราโดยไม่ต้องระบุ URL แบบเต็มในแต่ละครั้ง
ตอนนี้ในโฟลเดอร์ modules
ใน store
ให้สร้างไฟล์ชื่อ auth.js
//store/modules/auth.js import axios from 'axios'; const state = { }; const getters = { }; const actions = { }; const mutations = { }; export default { state, getters, actions, mutations };
state
ใน dict ของ state
เราจะกำหนดข้อมูลของเราและค่าเริ่มต้น:
const state = { user: null, posts: null, };
เรากำลังตั้งค่าเริ่มต้นของ state
ซึ่งเป็นอ็อบเจ็กต์ที่มี user
และ posts
ด้วยค่าเริ่มต้นเป็น null
การกระทำ
การกระทำคือฟังก์ชันที่ใช้ในการ commit
การกลายพันธุ์เพื่อเปลี่ยนสถานะหรือสามารถใช้เพื่อ dispatch
เช่นเรียกการกระทำอื่น มันสามารถถูกเรียกในองค์ประกอบหรือมุมมองที่แตกต่างกันและจากนั้นทำการกลายพันธุ์ของรัฐของเรา
ลงทะเบียนการดำเนินการ
การดำเนินการ Register
ของเราใช้ข้อมูลในแบบฟอร์ม ส่งข้อมูลไปยังปลายทาง /register
และกำหนดการตอบสนองให้กับการ response
ของตัวแปร ต่อไป เราจะจัดส่ง username
และ password
ของแบบฟอร์มเพื่อดำเนินการ login
ด้วยวิธีนี้ เราเข้าสู่ระบบผู้ใช้หลังจากที่พวกเขาลงทะเบียน ดังนั้นพวกเขาจะถูกเปลี่ยนเส้นทางไปยังหน้า /posts
async Register({dispatch}, form) { await axios.post('register', form) let UserForm = new FormData() UserForm.append('username', form.username) UserForm.append('password', form.password) await dispatch('LogIn', UserForm) },
เข้าสู่ระบบการดำเนินการ
นี่คือที่ที่การรับรองความถูกต้องหลักเกิดขึ้น เมื่อผู้ใช้กรอกชื่อผู้ใช้และรหัสผ่าน ระบบจะส่งผ่านไปยัง User
ซึ่งเป็นวัตถุ FormData ฟังก์ชัน LogIn
จะนำวัตถุ User
และส่งคำขอ POST
ไปยังปลายทาง /login
เพื่อเข้าสู่ระบบผู้ใช้
ในที่สุดฟังก์ชัน Login
จะมอบ username
ให้กับการกลายพันธุ์ setUser
async LogIn({commit}, User) { await axios.post('login', User) await commit('setUser', User.get('username')) },
สร้างการดำเนินการโพสต์
การดำเนินการ CreatePost
ของเราเป็นฟังก์ชันที่รับ post
และส่งไปยังจุดสิ้นสุด /post
ของเรา จากนั้นจึงส่งการดำเนินการ GetPosts
ซึ่งช่วยให้ผู้ใช้สามารถดูโพสต์ของตนได้หลังจากสร้าง
async CreatePost({dispatch}, post) { await axios.post('post', post) await dispatch('GetPosts') },
รับโพสต์การดำเนินการ
การดำเนินการ GetPosts
ของเราจะส่งคำขอ GET
ไปยังจุดปลาย /posts
เพื่อดึงข้อมูลโพสต์ใน API ของเรา และทำการเปลี่ยน setPosts
async GetPosts({ commit }){ let response = await axios.get('posts') commit('setPosts', response.data) },
ออกจากระบบ การดำเนินการ
async LogOut({commit}){ let user = null commit('logout', user) }
การ LogOut
การออกจากระบบจะลบ user
ของเราออกจากแคชของเบราว์เซอร์ มันทำได้โดยทำการ logout
:
การกลายพันธุ์
const mutations = { setUser(state, username){ state.user = username }, setPosts(state, posts){ state.posts = posts }, LogOut(state){ state.user = null state.posts = null }, };
การกลายพันธุ์แต่ละครั้งจะรับ state
และค่าจากการกระทำที่กระทำ ยกเว้น Logout
ค่าที่ได้รับใช้เพื่อเปลี่ยนบางส่วนหรือทั้งหมดหรือชอบใน LogOut
ตั้งค่าตัวแปรทั้งหมดกลับเป็น null
Getters
Getters เป็นฟังก์ชันในการรับสถานะ สามารถใช้ในหลายองค์ประกอบเพื่อรับสถานะปัจจุบัน ฟังก์ชัน isAuthenticatated
จะตรวจสอบว่า state.user
ถูกกำหนดหรือเป็น null และคืนค่า true
หรือ false
ตามลำดับ StatePosts
และ StateUser
ส่งคืนค่า state.posts
และ state.user
ตามลำดับ
const getters = { isAuthenticated: state => !!state.user, StatePosts: state => state.posts, StateUser: state => state.user, };
ตอนนี้ไฟล์ auth.js
ทั้งหมดของคุณควรคล้ายกับรหัสของฉันบน GitHub
การตั้งค่าส่วนประกอบ
1. NavBar.vue
และส่วนประกอบ App.vue
ในโฟลเดอร์ src/components
ของคุณ ให้ลบ HelloWorld.vue
และไฟล์ใหม่ชื่อ NavBar.vue
นี่คือส่วนประกอบสำหรับแถบนำทางของเรา ซึ่งจะเชื่อมโยงไปยังหน้าต่างๆ ของส่วนประกอบของเราที่ถูกกำหนดเส้นทางไว้ที่นี่ ลิงก์เราเตอร์แต่ละตัวชี้ไปที่เส้นทาง/หน้าในแอปของเรา
v-if="isLoggedIn"
เป็นเงื่อนไขในการแสดงลิงก์ Logout
หากผู้ใช้เข้าสู่ระบบและซ่อนเส้นทางการ Register
และ Login
เรามีวิธี logout
ซึ่งสามารถเข้าถึงได้เฉพาะผู้ใช้ที่ลงชื่อเข้าใช้ ซึ่งจะถูกเรียกเมื่อมีการคลิกลิงก์ Logout
มันจะส่งการ LogOut
การออกจากระบบแล้วนำผู้ใช้ไปยังหน้าเข้าสู่ระบบ
<template> <div> <router-link to="/">Home</router-link> | <router-link to="/posts">Posts</router-link> | <span v-if="isLoggedIn"> <a @click="logout">Logout</a> </span> <span v-else> <router-link to="/register">Register</router-link> | <router-link to="/login">Login</router-link> </span> </div> </template> <script> export default { name: 'NavBar', computed : { isLoggedIn : function(){ return this.$store.getters.isAuthenticated} }, methods: { async logout (){ await this.$store.dispatch('LogOut') this.$router.push('/login') } }, } </script> <style> #nav { padding: 30px; } #nav a { font-weight: bold; color: #2c3e50; } a:hover { cursor: pointer; } #nav a.router-link-exact-active { color: #42b983; } </style>
ตอนนี้แก้ไของค์ประกอบ App.vue
ของคุณให้มีลักษณะดังนี้:
<template> <div> <NavBar /> <router-view/> </div> </template> <script> // @ is an alias to /src import NavBar from '@/components/NavBar.vue' export default { components: { NavBar } } </script> <style> #app { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; } </style>
ที่นี่เรานำเข้าองค์ประกอบ NavBar ที่เราสร้างไว้ด้านบนและวางไว้ในส่วนเทมเพลตก่อน <router-view />
2. ดูส่วนประกอบ
ส่วนประกอบการดูคือหน้าต่างๆ ในแอปซึ่งจะถูกกำหนดภายใต้เส้นทางและสามารถเข้าถึงได้จากแถบนำทาง ในการเริ่มต้น ไปที่โฟลเดอร์ views
ลบองค์ประกอบ About.vue
และเพิ่มส่วนประกอบต่อไปนี้:

-
Home.vue
-
Register.vue
-
Login.vue
-
Posts.vue
Home.vue
เขียน Home.vue
ใหม่ให้มีลักษณะดังนี้:
<template> <div class="home"> <p>Heyyyyyy welcome to our blog, check out our posts</p> </div> </template> <script> export default { name: 'Home', components: { } } </script>
ซึ่งจะแสดงข้อความต้อนรับสำหรับผู้ใช้เมื่อเข้าสู่หน้าแรก
Register.vue
นี่คือหน้าที่เราต้องการให้ผู้ใช้ของเราสามารถลงทะเบียนในแอปพลิเคชันของเรา เมื่อผู้ใช้กรอกแบบฟอร์ม ข้อมูลจะถูกส่งไปยัง API และเพิ่มไปยังฐานข้อมูล จากนั้นเข้าสู่ระบบ
เมื่อดูที่ API ปลายทาง /register
ต้องการ username
, full_name
และ password
ของผู้ใช้ของเรา มาสร้างเพจและแบบฟอร์มเพื่อรับข้อมูลเหล่านี้กัน:
<template> <div class="register"> <div> <form @submit.prevent="submit"> <div> <label for="username">Username:</label> <input type="text" name="username" v-model="form.username"> </div> <div> <label for="full_name">Full Name:</label> <input type="text" name="full_name" v-model="form.full_name"> </div> <div> <label for="password">Password:</label> <input type="password" name="password" v-model="form.password"> </div> <button type="submit"> Submit</button> </form> </div> <p v-if="showError">Username already exists</p> </div> </template>
ในองค์ประกอบ Register
เราจะต้องเรียกการดำเนินการ Register
ซึ่งจะได้รับข้อมูลแบบฟอร์ม
<script> import { mapActions } from "vuex"; export default { name: "Register", components: {}, data() { return { form: { username: "", full_name: "", password: "", }, showError: false }; }, methods: { ...mapActions(["Register"]), async submit() { try { await this.Register(this.form); this.$router.push("/posts"); this.showError = false } catch (error) { this.showError = true } }, }, }; </script>
เราเริ่มต้นด้วยการนำเข้า mapActions
จาก Vuex สิ่งนี้คือการนำเข้าการกระทำจากร้านค้าของเราไปยังส่วนประกอบ ซึ่งช่วยให้เราสามารถเรียกการดำเนินการจากคอมโพเนนต์ได้
data()
มีค่าสถานะท้องถิ่นที่จะใช้ในองค์ประกอบนี้ เรามีวัตถุ form
ที่มี username
, full_name
และ password
โดยค่าเริ่มต้นของพวกเขาตั้งเป็นสตริงว่าง นอกจากนี้เรายังมี showError
ซึ่งเป็นบูลีนที่จะใช้เพื่อแสดงข้อผิดพลาดหรือไม่
ใน methods
ที่เรานำเข้าแอคชัน Register
โดยใช้ Mapactions
ไปยังส่วนประกอบ จึงสามารถเรียกแอคชัน Register
ได้ด้วยสิ่งนี้ this.Register
เรามีวิธีการส่งซึ่งเรียกการดำเนินการ Register
ซึ่งเราสามารถเข้าถึงได้โดยใช้ this.Register
ส่ง this.form
ไป หากไม่พบ error
เราจะใช้ this.$router
เพื่อส่งผู้ใช้ไปยังหน้าเข้าสู่ระบบ มิฉะนั้นเราตั้งค่า showError
เป็นจริง
เมื่อทำอย่างนั้นแล้ว เราสามารถใส่สไตล์ลงไปได้
<style scoped> * { box-sizing: border-box; } label { padding: 12px 12px 12px 0; display: inline-block; } button[type=submit] { background-color: #4CAF50; color: white; padding: 12px 20px; cursor: pointer; border-radius:30px; } button[type=submit]:hover { background-color: #45a049; } input { margin: 5px; box-shadow:0 0 15px 4px rgba(0,0,0,0.06); padding:10px; border-radius:30px; } #error { color: red; } </style>
Login.vue
หน้าเข้าสู่ระบบของเราคือที่ที่ผู้ใช้ที่ลงทะเบียนจะป้อน username
และ password
เพื่อรับการตรวจสอบสิทธิ์โดย API และลงชื่อเข้าใช้เว็บไซต์ของเรา
<template> <div class="login"> <div> <form @submit.prevent="submit"> <div> <label for="username">Username:</label> <input type="text" name="username" v-model="form.username" /> </div> <div> <label for="password">Password:</label> <input type="password" name="password" v-model="form.password" /> </div> <button type="submit">Submit</button> </form> <p v-if="showError">Username or Password is incorrect</p> </div> </div> </template>
ตอนนี้เราจะต้องส่งข้อมูลแบบฟอร์มของเราไปยังการดำเนินการที่ส่งคำขอแล้วส่งไปยัง Posts
หน้าที่ปลอดภัย
<script> import { mapActions } from "vuex"; export default { name: "Login", components: {}, data() { return { form: { username: "", password: "", }, showError: false }; }, methods: { ...mapActions(["LogIn"]), async submit() { const User = new FormData(); User.append("username", this.form.username); User.append("password", this.form.password); try { await this.LogIn(User); this.$router.push("/posts"); this.showError = false } catch (error) { this.showError = true } }, }, }; </script>
เรานำเข้า Mapactions
และใช้ในการนำเข้าการดำเนินการ LogIn
ไปยังส่วนประกอบ ซึ่งจะใช้ในฟังก์ชันการ submit
ของเรา
หลังจากการดำเนินการ Login
ผู้ใช้จะถูกเปลี่ยนเส้นทางไปยังหน้า /posts
ในกรณีที่เกิดข้อผิดพลาด จะตรวจพบข้อผิดพลาดและตั้งค่า ShowError
เป็นจริง
ตอนนี้ สไตล์บางอย่าง:
<style scoped> * { box-sizing: border-box; } label { padding: 12px 12px 12px 0; display: inline-block; } button[type=submit] { background-color: #4CAF50; color: white; padding: 12px 20px; cursor: pointer; border-radius:30px; } button[type=submit]:hover { background-color: #45a049; } input { margin: 5px; box-shadow:0 0 15px 4px rgba(0,0,0,0.06); padding:10px; border-radius:30px; } #error { color: red; } </style>
Posts.vue
หน้าโพสต์ของเราเป็นหน้าที่มีการรักษาความปลอดภัยซึ่งมีให้เฉพาะผู้ใช้ที่ตรวจสอบสิทธิ์แล้วเท่านั้น ในหน้านี้ พวกเขาสามารถเข้าถึงโพสต์ในฐานข้อมูลของ API สิ่งนี้ทำให้ผู้ใช้สามารถเข้าถึงโพสต์และยังทำให้พวกเขาสร้างโพสต์ไปยัง API ได้อีกด้วย
<template> <div class="posts"> <div v-if="User"> <p>Hi {{User}}</p> </div> <div> <form @submit.prevent="submit"> <div> <label for="title">Title:</label> <input type="text" name="title" v-model="form.title"> </div> <div> <textarea name="write_up" v-model="form.write_up" placeholder="Write up..."></textarea> </div> <button type="submit"> Submit</button> </form> </div> <div class="posts" v-if="Posts"> <ul> <li v-for="post in Posts" :key="post.id"> <div> <p>{{post.title}}</p> <p>{{post.write_up}}</p> <p>Written By: {{post.author.username}}</p> </div> </li> </ul> </div> <div v-else> Oh no!!! We have no posts </div> </div> </template>
ในโค้ดด้านบนนี้ เรามีแบบฟอร์มให้ผู้ใช้สร้างโพสต์ใหม่ได้ การส่งแบบฟอร์มควรทำให้การโพสต์ถูกส่งไปยัง API — เราจะเพิ่มวิธีการที่จะทำเช่นนั้นในไม่ช้า นอกจากนี้เรายังมีส่วนที่แสดงโพสต์ที่ได้รับจาก API (ในกรณีที่ผู้ใช้มี) หากผู้ใช้ไม่มีโพสต์ เราก็แสดงข้อความว่าไม่มีโพสต์
ตัวรับ StateUser
และ StatePosts
จะถูกจับคู่ เช่น นำเข้าโดยใช้ mapGetters
ไป Posts.vue
จากนั้นจะสามารถเรียกพวกมันในเทมเพลตได้
<script> import { mapGetters, mapActions } from "vuex"; export default { name: 'Posts', components: { }, data() { return { form: { title: '', write_up: '', } }; }, created: function () { // a function to call getposts action this.GetPosts() }, computed: { ...mapGetters({Posts: "StatePosts", User: "StateUser"}), }, methods: { ...mapActions(["CreatePost", "GetPosts"]), async submit() { try { await this.CreatePost(this.form); } catch (error) { throw "Sorry you can't make a post now!" } }, } }; </script>
เรามีสถานะเริ่มต้นสำหรับ form
ซึ่งเป็นอ็อบเจ็กต์ที่มี title
และ write_up
เป็นคีย์ และค่าต่างๆ ถูกตั้งค่าเป็นสตริงว่าง ค่าเหล่านี้จะเปลี่ยนเป็นสิ่งที่ผู้ใช้ป้อนลงในแบบฟอร์มในส่วนเทมเพลตของคอมโพเนนต์ของเรา
เมื่อผู้ใช้ส่งโพสต์ เราเรียก this.CreatePost
ซึ่งรับวัตถุแบบฟอร์ม
ดังที่คุณเห็นในวงจรชีวิตที่ created
เรามีสิ่งนี้ this.GetPosts
เพื่อดึงข้อมูลโพสต์เมื่อสร้างส่วนประกอบ
สไตล์บางอย่าง,
<style scoped> * { box-sizing: border-box; } label { padding: 12px 12px 12px 0; display: inline-block; } button[type=submit] { background-color: #4CAF50; color: white; padding: 12px 20px; cursor: pointer; border-radius:30px; margin: 10px; } button[type=submit]:hover { background-color: #45a049; } input { width:60%; margin: 15px; border: 0; box-shadow:0 0 15px 4px rgba(0,0,0,0.06); padding:10px; border-radius:30px; } textarea { width:75%; resize: vertical; padding:15px; border-radius:15px; border:0; box-shadow:0 0 15px 4px rgba(0,0,0,0.06); height:150px; margin: 15px; } ul { list-style: none; } #post-div { border: 3px solid #000; width: 500px; margin: auto; margin-bottom: 5px;; } </style>
2. การกำหนดเส้นทาง
ในไฟล์ router/index.js
ของเรา ให้นำเข้ามุมมองของเราและกำหนดเส้นทางสำหรับแต่ละมุมมอง
import Vue from 'vue' import VueRouter from 'vue-router' import store from '../store'; import Home from '../views/Home.vue' import Register from '../views/Register' import Login from '../views/Login' import Posts from '../views/Posts' Vue.use(VueRouter) const routes = [ { path: '/', name: 'Home', component: Home }, { path: '/register', name: "Register", component: Register, meta: { guest: true }, }, { path: '/login', name: "Login", component: Login, meta: { guest: true }, }, { path: '/posts', name: Posts, component: Posts, meta: {requiresAuth: true}, } ] const router = new VueRouter({ mode: 'history', base: process.env.BASE_URL, routes }) export default router
3. การจัดการผู้ใช้
- ผู้ใช้ที่ไม่ได้รับอนุญาต
หากคุณสังเกตเห็นในการกำหนดเส้นทางการโพสต์ของเรา เราได้เพิ่มmeta
คีย์เพื่อระบุว่าผู้ใช้ต้องได้รับการตรวจสอบสิทธิ์ ตอนนี้เราจำเป็นต้องมีเราเตอร์ ก่อนที่router.BeforeEach
นำทางแต่ละตัวจะตรวจสอบว่าเส้นทางมีคีย์meta: {requiresAuth: true}
หรือไม่ หากเส้นทางมีmeta
คีย์ ระบบจะตรวจสอบโทเค็นจากร้านค้า หากมี มันจะเปลี่ยนเส้นทางไปยังเส้นทางการlogin
const router = new VueRouter({ mode: 'history', base: process.env.BASE_URL, routes }) router.beforeEach((to, from, next) => { if(to.matched.some(record => record.meta.requiresAuth)) { if (store.getters.isAuthenticated) { next() return } next('/login') } else { next() } }) export default router
- ผู้ใช้ที่ได้รับอนุญาต
เรายังมีmeta
บนเส้นทาง/register
และ/login
meta: {guest: true}
จะหยุดผู้ใช้ที่เข้าสู่ระบบจากการเข้าถึงเส้นทางด้วย meta ของguest
router.beforeEach((to, from, next) => { if (to.matched.some((record) => record.meta.guest)) { if (store.getters.isAuthenticated) { next("/posts"); return; } next(); } else { next(); } });
ในที่สุด ไฟล์ของคุณควรเป็นแบบนี้:
import Vue from "vue"; import VueRouter from "vue-router"; import store from "../store"; import Home from "../views/Home.vue"; import Register from "../views/Register"; import Login from "../views/Login"; import Posts from "../views/Posts"; Vue.use(VueRouter); const routes = [ { path: "/", name: "Home", component: Home, }, { path: "/register", name: "Register", component: Register, meta: { guest: true }, }, { path: "/login", name: "Login", component: Login, meta: { guest: true }, }, { path: "/posts", name: "Posts", component: Posts, meta: { requiresAuth: true }, }, ]; const router = new VueRouter({ mode: "history", base: process.env.BASE_URL, routes, }); router.beforeEach((to, from, next) => { if (to.matched.some((record) => record.meta.requiresAuth)) { if (store.getters.isAuthenticated) { next(); return; } next("/login"); } else { next(); } }); router.beforeEach((to, from, next) => { if (to.matched.some((record) => record.meta.guest)) { if (store.getters.isAuthenticated) { next("/posts"); return; } next(); } else { next(); } }); export default router;
4.การจัดการโทเค็นที่หมดอายุ (คำขอต้องห้าม)
API ของเราถูกกำหนดให้หมดอายุโทเค็นหลังจาก 30 นาที ตอนนี้หากเราพยายามเข้าถึงหน้า posts
หลังจากผ่านไป 30 นาที เราได้รับข้อผิดพลาด 401
ซึ่งหมายความว่าเราต้องเข้าสู่ระบบอีกครั้ง ดังนั้นเราจะตั้งค่าตัวสกัดกั้นที่อ่านหากเราได้รับ ข้อผิดพลาด 401
จากนั้นระบบจะพาเรากลับไปที่หน้า login
เพิ่มข้อมูลโค้ดด้านล่างหลังการประกาศ URL เริ่มต้นของ Axios ในไฟล์ main.js
axios.interceptors.response.use(undefined, function (error) { if (error) { const originalRequest = error.config; if (error.response.status === 401 && !originalRequest._retry) { originalRequest._retry = true; store.dispatch('LogOut') return router.push('/login') } } })
สิ่งนี้ควรนำรหัสของคุณไปอยู่ในสถานะเดียวกับตัวอย่างบน GitHub
บทสรุป
หากคุณติดตามจนจบได้ ตอนนี้คุณน่าจะสร้างแอปพลิเคชันส่วนหน้าที่ทำงานได้อย่างเต็มประสิทธิภาพและปลอดภัย ตอนนี้ คุณได้เรียนรู้เพิ่มเติมเกี่ยวกับ Vuex และวิธีผสานรวมกับ Axios แล้ว รวมถึงวิธีบันทึกข้อมูลหลังจากโหลดซ้ำ
รหัสนี้มีอยู่ใน GitHub →
เว็บไซต์ที่โฮสต์:
https://nifty-hopper-1e9895.netlify.app/
API:
https://gabbyblog.herokuapp.com
เอกสาร API:
https://gabbyblog.herokuapp.com/docs
ทรัพยากร
- “การจัดการคุกกี้ด้วย Axios,” Aditya Srivastava, Medium
- “การสร้างการรับรองความถูกต้องของการนำทางใน Vue” ลอรี บาร์ธ จาก Ten Mile Square Blog
- “การเริ่มต้นใช้งาน Vuex” คู่มืออย่างเป็นทางการ
- “การตรวจสอบ Vue.js JWT ด้วย Vuex และ Vue Router” BezKoder