المصادقة في Vue.js

نشرت: 2022-03-10
ملخص سريع ↬ يحتاج كل تطبيق ويب يتعامل مع البيانات الخاصة بالمستخدم إلى تنفيذ المصادقة. إن معرفة كيفية القيام بذلك أمر مهم لمطوري Vue ، وهذا ما تهدف هذه المقالة إلى تسليط الضوء عليه. سيثبت هذا البرنامج التعليمي أنه مفيد للمطورين المبتدئين الذين يرغبون في التعرف على المصادقة في Vue. لكي تتمكن من المتابعة ، ستحتاج إلى معرفة جيدة بـ Vue و Vuex.

المصادقة هي ميزة ضرورية للغاية للتطبيقات التي تخزن بيانات المستخدم. إنها عملية للتحقق من هوية المستخدمين ، مما يضمن عدم تمكن المستخدمين غير المصرح لهم من الوصول إلى البيانات الخاصة - البيانات الخاصة بمستخدمين آخرين. هذا يؤدي إلى وجود مسارات مقيدة لا يمكن الوصول إليها إلا من قبل المستخدمين المصادق عليهم. يتم التحقق من هؤلاء المستخدمين المصادق عليهم باستخدام تفاصيل تسجيل الدخول الخاصة بهم (مثل اسم المستخدم / البريد الإلكتروني وكلمة المرور) وتعيين رمز مميز لهم لاستخدامه من أجل الوصول إلى الموارد المحمية للتطبيق.

في هذه المقالة ، ستتعرف على:

  1. تكوين Vuex مع Axios
  2. تحديد الطرق
  3. التعامل مع المستخدمين
  4. التعامل مع رمز منتهي الصلاحية

التبعيات

سنعمل مع التبعيات التالية التي تساعد في المصادقة:

  • أكسيوس
    لإرسال واسترجاع البيانات من API الخاص بنا
  • فويكس
    لتخزين البيانات التي تم الحصول عليها من API الخاص بنا
  • جهاز التوجيه Vue-Router
    للملاحة وحماية الطرق

سنعمل باستخدام هذه الأدوات ونرى كيف يمكنهم العمل معًا لتوفير وظائف مصادقة قوية لتطبيقنا.

واجهة برمجة تطبيقات Backend

سنقوم ببناء موقع مدونة بسيط ، والذي سيستفيد من واجهة برمجة التطبيقات هذه. يمكنك التحقق من المستندات لمعرفة نقاط النهاية وكيفية إرسال الطلبات.

من المستندات ، ستلاحظ إرفاق عدد قليل من نقاط النهاية بقفل. هذه طريقة لإظهار أن المستخدمين المصرح لهم فقط يمكنهم إرسال الطلبات إلى نقاط النهاية هذه. نقاط النهاية غير المقيدة هي نقاط نهاية /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 تُستخدم لإرسال الطلبات من المتصفح إلى واجهات برمجة التطبيقات. وفقًا لوثائق 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 إلى متجرنا.

الوحدات

الوحدات النمطية هي أقسام مختلفة من متجرنا تتعامل مع مهام متشابهة معًا ، بما في ذلك:

  • حالة
  • أجراءات
  • الطفرات
  • حاصل

قبل المتابعة ، دعنا نعدل ملف 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 بالإضافة إلى حزمة ./store .

كما ذكرنا سابقًا ، يجب تعيين ملف تعريف ارتباط رمز الوصول والبيانات الضرورية الأخرى التي تم الحصول عليها من واجهة برمجة التطبيقات في رؤوس الطلبات للطلبات المستقبلية. نظرًا لأننا سنستخدم 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

في 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 لجلب المنشورات في واجهة برمجة التطبيقات لدينا ويلتزم 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 اضبط جميع المتغيرات مرة أخرى على قيمة خالية.

حاصل

الحاصلون هم وظائف للحصول على الدولة. يمكن استخدامه في مكونات متعددة للحصول على الحالة الحالية. تتحقق الدالة isAuthenticatated إذا تم تعريف state.user أم لاغية وإرجاع 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 element الخاص بك ، احذف 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

هذه هي الصفحة التي نريد أن يتمكن المستخدمون لدينا من التسجيل في تطبيقنا. عندما يملأ المستخدمون النموذج ، يتم إرسال معلوماتهم إلى واجهة برمجة التطبيقات وإضافتها إلى قاعدة البيانات ثم تسجيل الدخول.

بالنظر إلى واجهة برمجة التطبيقات ، تتطلب نقطة نهاية /register username ، واسم كامل password full_name . لنقم الآن بإنشاء صفحة ونموذج للحصول على هذه المعلومات:

 <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 .

لدينا طريقة إرسال this.Register إجراء Register الذي يمكننا الوصول إليه this.form هذا. إذا لم يتم العثور على error فإننا نستفيد من this.$router لإرسال المستخدم إلى صفحة تسجيل الدخول. وإلا قمنا بتعيين showError على true.

بعد القيام بذلك ، يمكننا تضمين بعض التصميم.

 <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 الخاصة بهم للمصادقة عليها بواسطة واجهة برمجة التطبيقات وتسجيل الدخول إلى موقعنا.

 <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 على true.

الآن ، بعض التصميم:

 <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. يسمح هذا للمستخدمين بالوصول إلى المنشورات ويمكنهم أيضًا من إنشاء منشورات على واجهة برمجة التطبيقات.

 <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>

في الكود أعلاه ، لدينا نموذج للمستخدم ليتمكن من إنشاء مشاركات جديدة. يجب أن يؤدي إرسال النموذج إلى إرسال المنشور إلى واجهة برمجة التطبيقات - سنضيف الطريقة التي تقوم بذلك قريبًا. لدينا أيضًا قسم يعرض المنشورات التي تم الحصول عليها من واجهة برمجة التطبيقات (في حال كان لدى المستخدم أي منها). إذا لم يكن لدى المستخدم أية منشورات ، فإننا ببساطة نعرض رسالة مفادها أنه لا توجد مشاركات.

يتم تعيين معلمات 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. التعامل مع المستخدمين

  • المستخدمون غير المصرح لهم
    إذا لاحظت أثناء تحديد مسارات router.BeforeEach ، فقد meta مفتاحًا تعريفًا للإشارة إلى وجوب مصادقة المستخدم ، فنحن بحاجة الآن إلى جهاز توجيه. قبل كل حارس تنقل يقوم بالتحقق مما إذا كان المسار يحتوي على مفتاح التعريف 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.التعامل مع الرمز منتهي الصلاحية (الطلبات المحظورة)

تم تعيين واجهة برمجة التطبيقات الخاصة بنا على الرموز المميزة التي تنتهي صلاحيتها بعد 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

موارد

  • "التعامل مع ملفات تعريف الارتباط مع أكسيوس" ، Aditya Srivastava ، متوسط
  • "Creating an Authentication Navigation Guard In Vue" ، لوري بارث ، مدونة Ten Mile Square
  • "Getting Started with Vuex ،" الدليل الرسمي
  • "مصادقة Vue.js JWT مع موجه Vuex و Vue ،" BezKoder