Uwierzytelnianie w Vue.js
Opublikowany: 2022-03-10Uwierzytelnianie jest bardzo potrzebną funkcją dla aplikacji przechowujących dane użytkownika. Jest to proces weryfikacji tożsamości użytkowników, zapewniający, że nieupoważnieni użytkownicy nie mają dostępu do prywatnych danych — danych należących do innych użytkowników. Prowadzi to do posiadania ograniczonych tras, do których dostęp mają tylko uwierzytelnieni użytkownicy. Ci uwierzytelnieni użytkownicy są weryfikowani przy użyciu ich danych logowania (tj. nazwy użytkownika/adresu e-mail i hasła) i przypisując im token, który ma być używany w celu uzyskania dostępu do chronionych zasobów aplikacji.
W tym artykule dowiesz się o:
- Konfiguracja Vuex z Axios
- Definiowanie tras
- Obsługa użytkowników
- Obsługa wygasłego tokena
Zależności
Będziemy pracować z następującymi zależnościami, które pomagają w uwierzytelnianiu:
- Aksjos
Do wysyłania i pobierania danych z naszego API - Vuex
Do przechowywania danych pobranych z naszego API - Vue-Router
Do nawigacji i ochrony Tras
Będziemy pracować z tymi narzędziami i zobaczymy, jak mogą ze sobą współpracować, aby zapewnić niezawodne funkcje uwierzytelniania w naszej aplikacji.
Backend API
Zbudujemy prostą witrynę blogową, która będzie korzystać z tego API. Możesz zapoznać się z dokumentacją, aby zobaczyć punkty końcowe i sposób wysyłania żądań.
W dokumentach zauważysz, że kilka punktów końcowych jest połączonych zamkiem. Jest to sposób na pokazanie, że tylko autoryzowani użytkownicy mogą wysyłać żądania do tych punktów końcowych. Nieograniczonymi punktami końcowymi są punkty końcowe /register
i /login
. Błąd z kodem stanu 401
powinien zostać zwrócony, gdy nieuwierzytelniony użytkownik próbuje uzyskać dostęp do ograniczonego punktu końcowego.
Po pomyślnym zalogowaniu użytkownika, token dostępu wraz z niektórymi danymi zostanie odebrany w aplikacji Vue, który zostanie wykorzystany do ustawienia pliku cookie i dołączony w nagłówku żądania do wykorzystania w przyszłych żądaniach. Backend sprawdzi nagłówek żądania za każdym razem, gdy żądanie zostanie wysłane do ograniczonego punktu końcowego. Nie ulegaj pokusie przechowywania tokena dostępu w magazynie lokalnym.
Projekt rusztowania
Używając Vue CLI, uruchom poniższe polecenie, aby wygenerować aplikację:
vue create auth-project
Przejdź do swojego nowego folderu:
cd auth-project
Dodaj vue-router i zainstaluj więcej zależności — vuex i axios:
vue add router npm install vuex axios
Teraz uruchom swój projekt i powinieneś zobaczyć, co mam poniżej w swojej przeglądarce:
npm run serve
1. Konfiguracja Vuex z Axios
Axios to biblioteka JavaScript używana do wysyłania żądań z przeglądarki do interfejsów API. Zgodnie z dokumentacją Vuex;
„Vuex to wzorzec zarządzania stanem + biblioteka dla aplikacji Vue.js. Służy jako scentralizowany magazyn dla wszystkich komponentów aplikacji, z regułami zapewniającymi, że stan można zmienić tylko w przewidywalny sposób”.
Co to znaczy? Vuex to sklep używany w aplikacji Vue, który pozwala nam na zapisanie danych, które będą dostępne dla każdego komponentu i zapewnią sposoby zmiany tych danych. Użyjemy Axios w Vuex do wysyłania naszych próśb i wprowadzania zmian w naszym stanie (danych). Axios będzie używany w actions
Vuex do wysyłania GET
i POST
, otrzymana odpowiedź zostanie wykorzystana do wysłania informacji do mutations
i aktualizacji danych naszego sklepu.
Aby poradzić sobie z resetowaniem Vuex po odświeżeniu, będziemy pracować z vuex-persistedstate
, biblioteką, która przechowuje nasze dane Vuex między kolejnymi ładowaniami strony.
npm install --save vuex-persistedstate
Teraz stwórzmy nowy store
folderów w src
, do konfiguracji sklepu Vuex. W folderze store
utwórz nowy folder; modules
i plik index.js
. Należy pamiętać, że musisz to zrobić tylko wtedy, gdy folder nie zostanie automatycznie utworzony.
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()] });
Tutaj korzystamy z Vuex
i importujemy module
auth z folderu modules
do naszego sklepu.
Moduły
Moduły to różne segmenty naszego sklepu, które wspólnie realizują podobne zadania, w tym:
- stan
- działania
- mutacje
- zbieracze
Zanim przejdziemy dalej, edytujmy nasz plik 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')
Zaimportowaliśmy obiekt store
z folderu ./store
oraz z pakietu Axios.
Jak wspomniano wcześniej, plik cookie tokena dostępu i inne niezbędne dane uzyskane z interfejsu API należy ustawić w nagłówkach żądań dla przyszłych żądań. Ponieważ będziemy używać Axios podczas wysyłania żądań, musimy skonfigurować Axios, aby z niego korzystał. W powyższym fragmencie robimy to za pomocą axios.defaults.withCredentials = true
, jest to potrzebne, ponieważ domyślnie pliki cookie nie są przekazywane przez Axios.
aaxios.defaults.withCredentials = true
to instrukcja dla Axios, aby wysłać wszystkie żądania z danymi uwierzytelniającymi, takimi jak; nagłówki autoryzacyjne, certyfikaty klienta TLS lub pliki cookie (jak w naszym przypadku).
Ustawiamy nasz axios.defaults.baseURL
dla naszego żądania Axios do naszego API
W ten sposób, kiedy wysyłamy przez Axios, używa on tego podstawowego adresu URL. Dzięki temu możemy dodać tylko nasze punkty końcowe, takie jak /register
i /login
, do naszych działań bez podawania pełnego adresu URL za każdym razem.
Teraz w folderze modules
w store
utwórz plik o nazwie 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
W naszym dykcie state
zdefiniujemy nasze dane i ich domyślne wartości:
const state = { user: null, posts: null, };
Ustawiamy domyślną wartość state
, która jest obiektem zawierającym user
i posts
z ich początkowymi wartościami jako null
.
działania
dispatch
to funkcje, które są używane do commit
mutacji w celu zmiany stanu lub mogą być użyte do wywołania innej akcji. Można go wywoływać w różnych komponentach lub poglądach, a następnie dokonuje mutacji naszego stanu;
Zarejestruj działanie
Nasza akcja Register
pobiera dane z formularza, wysyła dane do naszego punktu końcowego /register
i przypisuje odpowiedź do zmiennej response
. Następnie wyślemy naszą username
i password
z formularza do naszej akcji login
. W ten sposób logujemy użytkownika po jego zarejestrowaniu się, dzięki czemu zostaje przekierowany na stronę /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) },
Akcja logowania
Tutaj odbywa się główne uwierzytelnianie. Gdy użytkownik wprowadzi swoją nazwę użytkownika i hasło, jest to przekazywane do User
, który jest obiektem FormData, funkcja LogIn
pobiera obiekt User
i wysyła żądanie POST
do punktu końcowego /login
w celu zalogowania użytkownika.
Funkcja Login
ostatecznie zatwierdza username
do mutacji setUser
.
async LogIn({commit}, User) { await axios.post('login', User) await commit('setUser', User.get('username')) },
Utwórz akcję posta
Nasza akcja CreatePost
to funkcja, która pobiera post
i wysyła go do naszego punktu końcowego /post
, a następnie wywołuje akcję GetPosts
. Dzięki temu użytkownik może zobaczyć swoje posty po utworzeniu.
async CreatePost({dispatch}, post) { await axios.post('post', post) await dispatch('GetPosts') },
Pobierz akcję postów
Nasza akcja GetPosts
wysyła żądanie GET
do naszego punktu końcowego /posts
w celu pobrania postów w naszym API i zatwierdza mutację setPosts
.
async GetPosts({ commit }){ let response = await axios.get('posts') commit('setPosts', response.data) },
Wyloguj Akcja
async LogOut({commit}){ let user = null commit('logout', user) }
Nasza akcja LogOut
usuwa naszego user
z pamięci podręcznej przeglądarki. Robi to poprzez logout
:
Mutacje
const mutations = { setUser(state, username){ state.user = username }, setPosts(state, posts){ state.posts = posts }, LogOut(state){ state.user = null state.posts = null }, };
Każda mutacja przyjmuje state
i wartość z akcji ją dokonującej, oprócz Logout
. Otrzymana wartość jest używana do zmiany niektórych części lub wszystkich lub podobnie jak w LogOut
, ustaw wszystkie zmienne z powrotem na null.
Gettery
Gettery to funkcje umożliwiające uzyskanie stanu. Może być używany w wielu komponentach, aby uzyskać aktualny stan. Funkcja isAuthenticatated
sprawdza, czy state.user
jest zdefiniowany lub null i zwraca odpowiednio true
lub false
. StatePosts
i StateUser
zwracają odpowiednio wartość state.posts
i state.user
.
const getters = { isAuthenticated: state => !!state.user, StatePosts: state => state.posts, StateUser: state => state.user, };
Teraz cały plik auth.js
powinien przypominać mój kod na GitHub.
Konfigurowanie komponentów
1. Komponenty NavBar.vue
i App.vue
W folderze src/components
usuń plik HelloWorld.vue
i nowy plik o nazwie NavBar.vue
.
To jest komponent naszego paska nawigacyjnego, linki do różnych stron naszego komponentu zostały tutaj przekierowane. Każde łącze routera wskazuje trasę/stronę w naszej aplikacji.
v-if="isLoggedIn"
jest warunkiem wyświetlenia łącza Logout
, jeśli użytkownik jest zalogowany i ukrycia tras Register
i Login
. Mamy metodę logout
, która może być dostępna tylko dla zalogowanych użytkowników, zostanie wywołana po kliknięciu łącza Logout
. Wywoła akcję LogOut
, a następnie skieruje użytkownika do strony logowania.
<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>
Teraz edytuj swój komponent App.vue
, aby wyglądał tak:
<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>
Tutaj zaimportowaliśmy komponent NavBar, który utworzyliśmy powyżej i umieściliśmy w sekcji szablonu przed <router-view />
.
2. Widoki Komponenty
Komponenty widoków to różne strony w aplikacji, które zostaną zdefiniowane w ramach trasy i można do nich uzyskać dostęp z paska nawigacyjnego. Na początek Przejdź do folderu views
, usuń komponent About.vue
i dodaj następujące komponenty:
-
Home.vue
-
Register.vue
-
Login.vue
-
Posts.vue
Home.vue
Przepisz Home.vue
, aby wyglądał tak:
<template> <div class="home"> <p>Heyyyyyy welcome to our blog, check out our posts</p> </div> </template> <script> export default { name: 'Home', components: { } } </script>
Spowoduje to wyświetlenie tekstu powitalnego dla użytkowników odwiedzających stronę główną.
Register.vue
To jest strona, którą chcemy, aby nasi użytkownicy mogli zarejestrować się w naszej aplikacji. Gdy użytkownicy wypełnią formularz, ich informacje są przesyłane do API i dodawane do bazy danych, a następnie logowane.
Patrząc na API, punkt końcowy /register
wymaga username
, full_name
nazwy i password
naszego użytkownika. Teraz utwórzmy stronę i formularz, aby uzyskać te informacje:
<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>
W komponencie Register
musimy wywołać akcję Register
, która otrzyma dane z formularza.
<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>
Zaczynamy od importu mapActions
z Vuex, co polega na zaimportowaniu akcji z naszego sklepu do komponentu. To pozwala nam wywołać akcję z komponentu.
data()
zawiera lokalną wartość stanu, która będzie używana w tym komponencie, mamy obiekt form
, który zawiera username
, full_name
i password
, z ich początkowymi wartościami ustawionymi na pusty ciąg. Mamy również showError
, który jest wartością logiczną, która służy do pokazywania błędu lub nie.
W methods
importujemy akcję Register
za pomocą Mapactions
do komponentu, dzięki czemu można wywołać akcję Register
z this.Register
.
Mamy metodę submit , która wywołuje akcję Register
, do której mamy dostęp za pomocą this.Register
, wysyłając this.form
. Jeśli nie zostanie napotkany żaden error
, użyjemy this.$router
, aby wysłać użytkownika na stronę logowania. W przeciwnym razie ustawiamy showError
na true.
Po wykonaniu tej czynności możemy dodać trochę stylizacji.
<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
Na naszej stronie logowania zarejestrowani użytkownicy wprowadzą swoją username
i password
w celu uwierzytelnienia przez API i zalogowania się na naszej stronie.
<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>
Teraz musimy przekazać dane naszego formularza do akcji, która wysyła żądanie, a następnie przekazać je na bezpieczną stronę 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>
Importujemy Mapactions
i używamy go do zaimportowania akcji LogIn
do komponentu, który będzie używany w naszej funkcji submit
.
Po wykonaniu akcji Login
użytkownik zostaje przekierowany na stronę /posts
. W przypadku błędu, błąd jest przechwytywany, a ShowError
jest ustawiane na true.
Teraz trochę stylizacji:
<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
Nasza strona Posty to zabezpieczona strona, która jest dostępna tylko dla uwierzytelnionych użytkowników. Na tej stronie uzyskują dostęp do postów w bazie danych API. Pozwala to użytkownikom na dostęp do postów, a także umożliwia tworzenie postów do 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>
W powyższym kodzie mamy formularz umożliwiający użytkownikowi tworzenie nowych postów. Przesłanie formularza powinno spowodować wysłanie posta do API — wkrótce dodamy metodę, która to robi. Mamy również sekcję, która wyświetla posty uzyskane z API (w przypadku, gdy użytkownik je posiada). Jeśli użytkownik nie ma żadnych postów, po prostu wyświetlamy komunikat, że nie ma postów.
StateUser
i StatePosts
są mapowane, tj. importowane za pomocą mapGetters
do Posts.vue
, a następnie można je wywołać w szablonie.
<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>
Mamy stan początkowy dla form
, czyli obiektu, którego klucze to title
i write_up
, a wartości są ustawione na pusty ciąg. Te wartości zmienią się na dowolne, które użytkownik wprowadzi w formularzu w sekcji szablonu naszego komponentu.
Gdy użytkownik przesyła post, wywołujemy this.CreatePost
, który otrzymuje obiekt formularza.
Jak widać w created
cyklu życia, mamy this.GetPosts
do pobierania postów po utworzeniu komponentu.
Trochę stylizacji,
<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. Definiowanie tras
W naszym router/index.js
zaimportuj nasze widoki i zdefiniuj trasy dla każdego z nich
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. Obsługa użytkowników
- Nieautoryzowani użytkownicy
Jeśli zauważyłeś, że podczas definiowania tras naszych postów dodaliśmy kluczmeta
, aby wskazać, że użytkownik musi zostać uwierzytelniony, teraz musimy miećrouter.BeforeEach
. Przed każdym strażnikiem nawigacji, który sprawdza, czy trasa ma kluczmeta: {requiresAuth: true}
. Jeśli trasa ma kluczmeta
, sprawdza sklep pod kątem tokena; jeśli jest obecny, przekierowuje ich na ścieżkę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
- Autoryzowani użytkownicy
Mamy równieżmeta
na trasach/register
i/login
.meta: {guest: true}
uniemożliwia zalogowanym użytkownikom dostęp do tras z metaguest
.
router.beforeEach((to, from, next) => { if (to.matched.some((record) => record.meta.guest)) { if (store.getters.isAuthenticated) { next("/posts"); return; } next(); } else { next(); } });
W końcu twój plik powinien wyglądać tak:
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. Obsługa wygasłego tokena (zakazane żądania)
Nasze API jest ustawione na wygaśnięcie tokenów po 30 minutach, teraz jeśli spróbujemy uzyskać dostęp do strony posts
po 30 minutach, otrzymamy błąd 401
, co oznacza, że musimy się ponownie zalogować, więc ustawimy przechwytywacz, który odczytuje, czy otrzymamy Błąd 401
to przekierowuje nas z powrotem do strony login
.
Dodaj poniższy fragment kodu po deklaracji domyślnego adresu URL Axios w pliku 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') } } })
Powinno to doprowadzić Twój kod do tego samego stanu, co przykład na GitHub.
Wniosek
Jeśli udało Ci się doczekać końca, powinieneś być w stanie zbudować w pełni funkcjonalną i bezpieczną aplikację typu front-end. Teraz dowiedziałeś się więcej o Vuex i jak zintegrować go z Axios, a także jak zapisywać dane po ponownym załadowaniu.
Kod dostępny na GitHub →
Witryna hostowana:
https://nifty-hopper-1e9895.netlify.app/
API:
https://gabbyblog.herokuapp.com
Dokumentacja API:
https://gabbyblog.herokuapp.com/docs
Zasoby
- „Obsługa ciasteczek za pomocą Axios”, Aditya Srivastava, Medium
- „Tworzenie uwierzytelniającego strażnika nawigacyjnego w Vue”, Laurie Barth, blog Ten Mile Square
- „Pierwsze kroki z Vuex”, oficjalny przewodnik
- „Uwierzytelnianie Vue.js JWT za pomocą routera Vuex i Vue”, BezKoder