navigation gaurd not working properly - vue.js

I store the log in status of the user in my store.js (using vuex for state management)
When the user is logged in the login status is set to true in store.js
I check if the user is logged in and using v-if i hide the login button . Till he everything works fine
Now for checking purpose i removed the v-if condition on login button
I set up á before enter navigation guard in my !ogin.vue component as below
login.vue
beforeRouteEnter(to, from, next){
next(vm => {
if(vm.$store.getters.g_loginStatus === true){
next('/');
}else{
next();
}
})
}
If the user is logged in and presses the login button he is redirected to the home page
This works fine as the navigation guard is set up.
but the problem arises when i directly type in the login component url (localhost:8080/login) in the search.
The login component gets loaded normally without getting redirected to home page...
Why does this happen¿ Am i doing something wrong
I enen tried another approach using route meta fields following the documentation at route meta fields
But same problem
when i type the direct url to login component in search not getting redirected
import Vue from 'vue'
import Vuex from 'vuex'
import * as firebase from 'firebase'
Vue.use(Vuex);
export const store = new Vuex.Store({
state: {
loggedIn: false,
userName: 'Guest',
error: {
is: false,
errorMessage: ''
},
toast: {
is: false,
toastMessage: ''
}
},
getters: {
g_loginStatus: state => {
return state.loggedIn;
},
g_userName: state => {
return state.userName;
},
g_error: state => {
return state.error;
},
g_toast: (state) => {
return state.toast;
}
},
mutations: {
m_logInUser: (state) => {
state.loggedIn = true;
},
m_loggedOut: (state) => {
state.loggedIn = false;
}
},
actions: {
a_logInUser: ({state, dispatch}, user) => {
return new Promise((resolve, reject) => {
firebase.auth().signInWithEmailAndPassword(user.e, user.p).then(
() =>{
resolve(dispatch('a_authStateObserver'));
}, error => {
state.error.is = true;
let errorCode = error.code;
let errorMessage = error.message;
if (errorCode === 'auth/wrong-password') {
state.error.errorMessage = 'Wrong password.';
} else {
state.errorMessage = errorMessage;
}
}
);
});
},
a_loggedOut: () => {
firebase.auth().signOut().then(() => {
dispatch('a_authStateObserver');
});
},
a_signUpUser: ({state, dispatch}, user) => {
return new Promise((resolve, reject) => {
firebase.auth().createUserWithEmailAndPassword(user.e, user.p).then(
(u) =>{
let uid = u.uid;
resolve(dispatch('a_authStateObserver'));
}, error => {
state.error.is = true;
let errorCode = error.code;
let errorMessage = error.message;
if (errorCode === 'auth/wrong-password') {
state.error.errorMessage = 'Wrong password.';
} else {
state.errorMessage = errorMessage;
}
}
);
});
},
a_authStateObserver: ({commit, state}) => {
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
var displayName = user.displayName;
state.userName = user.email;
state.error.is = false;
commit('m_logInUser');
} else {
// User is signed out.
commit('m_loggedOut');
}
});
}
}
});
login.vue
<template>
<div class="container">
<div class="row">
<div class="form_bg center-block">
<form #submit.prevent="loginUser">
<h3 class="text-center">Log in</h3>
<br/>
<div class="form-group">
<input v-model="email" type="email" class="form-control" placeholder="Your Email">
</div>
<div class="form-group">
<input v-model="password" type="password" class="form-control" placeholder="Password">
</div>
<div class="align-center">
<p class="error" v-if="g_error.is">{{ g_error.errorMessage }}</p>
<button type="submit" class="btn btn-success center-block">Log in</button>
</div>
</form>
<br>
<p style="display:inline-block">Don't have an account?</p>
<router-link to="/signup" tag="a" style="display:inline-block">Sign up</router-link>
</div>
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
export default{
data(){
return{
email: '',
password: ''
};
},
methods: {
loginUser(){
this.$store.dispatch('a_logInUser', {e: this.email, p: this.password}).then(() =>{
this.$router.replace('/statuses');
});
}
},
computed: {
...mapGetters([
'g_error'
])
},
beforeRouteEnter(to, from, next){
next(vm => {
console.log(vm.$store.getters.g_loginStatus);
if(vm.$store.getters.g_loginStatus === true){
next('/');
}else{
next();
}
})
}
}
**routs.js**
import Home from './components/Home.vue'
import Users from './components/user/Users.vue'
import Statuses from './components/user/Statuses.vue'
import Post from './components/Post.vue'
import UserStatus from './components/user/UserStatus.vue'
import Signup from './components/auth/Signup.vue'
import Login from './components/auth/Login.vue'
export const routes = [
{path: '/', component: Home, name:'home'},
{path: '/users', component: Users, name:'users'},
{path: '/statuses', component: Statuses, name:'statuses'},
{path: '/current', component: UserStatus, name:'currentUser'},
{path: '/signup', component: Signup, name:'signup'},
{path: '/login', component: Login, name:'login'},
{path: '/post', component: Post}
];

Related

Uncaught TypeError: Unable to read undefined properties (reading '$store')

Login Vue
<template>
<div class="container mt-5">
<div class="row">
<div class="col-md-12">
<div class="col-md-6">
<div class="form-group">
<form #submit.prevent="onSubmit">
<label>Kullanıcı Adı</label>
<input
type="text"
class="form-control"
v-model="userdata.username"
/>
<br />
<label>Şifre</label>
<input class="form-control" v-model="userdata.password" />
<br />
<button class="btn btn-primary">Login</button>
</form>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { reactive } from "vue";
const userdata = reactive({
username: "",
password: "",
});
function loginAction() {
this.$store.dispatch("loginPost", userdata.value);
this.$router.push({ path: "/city" });
}
function onSubmit(event) {
event.preventDefault();
loginAction();
}
</script>
<style></style>
store kısmı import { createStore } from "vuex";
export default createStore({
state: {
cities: [],
user: {},
token: null,
},
getters: {},
mutations: {
setToken(state, token) {
state.token = token;
localStorage.setItem("token", token);
},
setUser(state, user) {
state.user = user;
localStorage.setItem("user", JSON.stringify(user));
},
},
actions: {
async login({ commit }, credentials) {
const response = await fetch("https://localhost:7254/api/Auth/login", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(credentials),
});
const data = await response.json();
if (response.ok) {
commit("setUser", data.user);
commit("setToken", data.token);
}
return response.ok;
},
},
});
store js
import { createStore } from "vuex";
export default createStore({
state: {
cities: [],
user: {},
token: null,
},
getters: {},
mutations: {
setToken(state, token) {
state.token = token;
localStorage.setItem("token", token);
},
setUser(state, user) {
state.user = user;
localStorage.setItem("user", JSON.stringify(user));
},
},
actions: {
async login({ commit }, credentials) {
const response = await fetch("https://localhost:7254/api/Auth/login", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(credentials),
});
const data = await response.json();
if (response.ok) {
commit("setUser", data.user);
commit("setToken", data.token);
}
return response.ok;
},
},
});
router js
import { createRouter, createWebHistory } from "vue-router";
import { city } from "#/components/City.vue";
import { Login } from "#/components/Login.vue";
import { home } from "#/components/Home.vue";
const routes = [
{
name: "login",
path: "/login",
component: Login,
},
{
name: "city",
path: "/city",
component: city,
},
{
name: "home",
path: "/",
component: home,
},
];
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes,
});
router.beforeEach((to, next) => {
// localStorage'daki JWT token'ı ve kullanıcı bilgilerini kontrol edin
const token = localStorage.getItem("token");
const user = JSON.parse(localStorage.getItem("user"));
// JWT token veya kullanıcı bilgisi yoksa, giriş sayfasına yönlendirin
// Eğer zaten giriş sayfasına gidiyorsak, yönlendirmeyi iptal edin
if (!token || !user) {
next({ path: "/login" });
}
next();
});
export default router;
main js
import { createApp } from "vue";
import App from "./App.vue";
import store from "../src/store";
import router from "../src/router";
// eslint-disable-next-line no-unused-vars
import bootstrap from "bootstrap/dist/css/bootstrap.min.css";
createApp(App).use(router).use(store).mount("#app");
Home vue
<!-- eslint-disable vue/multi-word-component-names -->
<template>
<h1>anasayfa Vue</h1>
<city />
<login />
</template>
<script setup>
import city from "#/components/City.vue";
import login from "#/components/Login.vue";
</script>
<style></style>
For example, when the page loads, I want it to go directly to the login page because in my router js file, I wrote the condition that it goes directly to the login page if there is no token and user with beforeEach, but it does not work, it gives this warning console log [Vue Router warn]: Unexpected error while initializing the router: TypeError: next is not a function After filling out and submitting the form, I get the following error Uncaught TypeError: Unable to read undefined properties (reading '$store')
first of all "this" doesn't refer to vue instance ,it refers to loginAction block,use arrow function instead ,secondly due to docs you should use useStore() method to get store in vue 3 Composition api

Attempts with creating authorization to site turns out to: Error POST 404 (OK)

I can't get how to solve problem with POST request.
I am trying implement authorization on my site (via Vuejs,vuex,vue-router, axios).
I will be very pleasure, if you give me some advice.
I searched info on forums , but situation was not the same.
Why 404 (OK)? If OK, why 404?
It means, that server received my data, but can't compare correct this or not?
I have components/pages:
App.vue
<template>
<div id="app">
<div id="nav">
<router-link to="/">Home page</router-link> |
<router-link to="/login">Login</router-link>
<span v-if="isLoggedIn"> | <a #click="logout">Logout</a></span>
</div>
<router-view/>
</div>
</template>
<script>
export default {
name: 'App',
computed : {
isLoggedIn : function(){ return this.$store.getters.isLoggedIn}
},
methods: {
logout: function () {
this.$store.dispatch('logout')
.then(() => {
this.$router.push('/login')
})
}
},
created: function () {
this.http.interceptors.response.use(function (err) {
return new Promise(function (resolve) {
if (err.status === 401 && err.config && !err.config.__isRetryRequest) {
this.$store.dispatch("logout")
resolve()
}
throw err;
});
});
},
}
</script>
LoginAnalytics.vue
Here user must input his mobile phone and password.
<template>
<div>
<form class="login" #submit.prevent="login">
<h1>Sign in</h1>
<label>Mobile</label>
<input required v-model="mobile" type="tel" placeholder="mobile phone"/>
<label>Password</label>
<input required v-model="password" type="password" placeholder="Password"/>
<hr/>
<button type="submit">Login</button>
</form>
</div>
</template>
<script>
export default {
data(){
return {
mobile : "",
password : ""
}
},
methods: {
login: function () {
let login = this.mobile
let password = this.password
this.$store.dispatch('login', { login, password })
.then(() => this.$router.push('/secure'))
.catch(err => console.log(err))
}
}
}
</script>
Vuex store
Here I am creating axios POST requests to server.
import Vue from 'vue';
import Vuex from 'vuex';
import axios from 'axios';
import { API_BASE_URL, TEMPORARY_TOKEN } from '../config';
Vue.use(Vuex);
export default new Vuex.Store({
state:{
trainings: [],
incomings: [],
sources: [],
avgShedule: [],
metro: [],
conversion: [],
avgIncome: [],
status: '',
token: localStorage.getItem('token') || '',
user : {},
},
mutations:{
auth_request(state){
state.status = 'loading'
},
auth_success(state, token, user){
state.status = 'success'
state.token = token
state.user = user
},
auth_error(state){
state.status = 'error'
},
logout(state){
state.status = ''
state.token = ''
},
},
getters:{
isLoggedIn: state => !!state.token,
authStatus: state => state.status,
},
actions:{
login({commit}, user){
return new Promise((resolve, reject) => {
commit('auth_request')
axios({
url: `${API_BASE_URL}/analytics.auth`,
data: user,
method: 'POST',
headers: {
"Content-Type": "application/x-www-form-urlencoded",
}
})
.then(resp => {
const token = resp.data.token
const user = resp.data.user
localStorage.setItem('token', token)
axios.defaults.headers.common['Authorization'] = token
commit('auth_success', token, user)
resolve(resp)
})
.catch(err => {
commit('auth_error')
localStorage.removeItem('token')
reject(err)
})
})
},
logout({commit}){
return new Promise((resolve) => {
commit('logout')
localStorage.removeItem('token')
delete axios.defaults.headers.common['Authorization']
resolve()
})
}
}
},
)
router.
There all refs to components and pages
import Vue from 'vue'
import Router from 'vue-router'
import store from '#/store'
import Analytics from '#/pages/Analytics-test.vue'
import LoginAnalytics from '#/components/LoginAnalytics.vue'
import HomeAnalytics from '#/components/HomeAnalytics.vue'
Vue.use(Router)
let router = new Router({
mode: 'history',
routes: [
{
path: '/',
name: 'home',
component: HomeAnalytics
},
{
path: '/login',
name: 'login',
component: LoginAnalytics
},
{
path: '/secure',
name: 'secure',
component: Analytics,
meta: {
requiresAuth: true
}
},
]
})
router.beforeEach((to, from, next) => {
if(to.matched.some(record => record.meta.requiresAuth)) {
if (store.getters.isLoggedIn) {
next()
return
}
next('/login')
} else {
next()
}
})
export default router
And also main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router';
import store from './store'
import axios from 'axios'
Vue.config.productionTip = false
Vue.prototype.$http = axios;
const token = localStorage.getItem('token')
if (token) {
Vue.prototype.$http.defaults.headers.common['Authorization'] = token
}
new Vue({
store,
router,
render: h => h(App),
}).$mount('#app')
Every time, when I am try login me with correct mobile and password, I received error like this:
Problem was with mistake in API endpoint.
All times I tried call this url:
url: ${API_BASE_URL}/analytics.auth,
But correct is:
url: ${API_BASE_URL}/account.auth.

Why my vue components don't update when the state in pinia changes?

I'm working on a website that uses vue and firebase. After the authentication part the user gets to the dashboard where there is the list of his projects that are a subcollection of the user document in firestore.
I made a pinia store that manages this data and each time a project is created with the form or gets deleted the state.projects updates with the new array of projects that gets cycled to display the list in the view.
Inside the view I have access to the store.projects thanks to a getter that should be reactive but when I add or delete a project nothing happens in the view, but still the state.projects gets updated.
here is the code of the DashboardView.vue:
<template>
<MainHeader mode="dashboard" />
<main class="main">
<div class="main__container">
<section class="main__section">
<div class="section__header">
<h1 class="header__title">Projects</h1>
<!-- <TextInput type="text" placeholder="Search" v-model="filter" /> -->
</div>
<div class="section__content">
<ul class="content__list">
<li
v-for="project in projects"
:key="project.id"
class="content__item"
>
{{ project.id }}
<!-- <router-link
:to="{ name: 'ProjectView', params: { id: project.id} }">
</router-link> -->
<SimpleButton #click="deleteProject(project.id)" type="button" text="delete" />
</li>
</ul>
</div>
<div class="section__footer">
<form #submit.prevent="createProject">
<TextInput type="text" placeholder="name" v-model="form.id" />
<TextInput type="text" placeholder="website" v-model="form.website" />
<SimpleButton type="submit" text="Add" />
</form>
</div>
</section>
</div>
</main>
</template>
<script>
import { useUserDataStore } from "../stores/UserDataStore.js";
import MainHeader from "../components/MainHeader.vue";
import SimpleButton from "../components/SimpleButton.vue";
import TextInput from "../components/TextInput.vue";
import { ref } from '#vue/reactivity';
export default {
name: "DashboardView",
components: {
MainHeader,
SimpleButton,
TextInput,
},
setup() {
// const filter = "";
const form = ref({});
const userDataStore = useUserDataStore();
const projects = userDataStore.getProjects;
const createProject = () => {
userDataStore.createProject(form.value)
}
const deleteProject = (id) => {
userDataStore.deleteProject(id)
}
return {
projects,
form,
createProject,
deleteProject,
};
},
};
</script>
And here the pinia store code:
import { defineStore } from "pinia";
import router from "../router";
import { db } from '../firebase';
import { doc, setDoc, getDoc, getDocs, collection, deleteDoc } from 'firebase/firestore'
export const useUserDataStore = defineStore('UserDataStore', {
state: () => {
userData: { }
projects: []
uid: null
},
actions: {
createNewUser(uid, name) {
setDoc(doc(db, "users", uid), {
name
})
.then(() => {
this.fetchUserData(uid)
})
.catch((error) => console.log(error))
},
fetchUserData(uid) {
this.uid = uid
// Fetch user doc with uid
getDoc(doc(db, "users", uid))
.then((response) => {
this.userData = response.data()
// Fetch user projects
getDocs(collection(db, "users", uid, "projects"))
.then((response) => {
const projectsArray = []
response.forEach(el => {
projectsArray.push({ data: el.data(), id: el.id})
})
this.projects = projectsArray
console.log(this.projects);
router.push({ name: 'DashboardView' })
})
})
.catch((error) => console.log(error))
},
createProject(details) {
const { id, website } = details
setDoc(doc(db, "users", this.uid, "projects", id), {
website
}).then(() => {
console.log('created');
this.fetchUserData(this.uid)
})
.catch((err) => console.log(err))
},
deleteProject(id) {
deleteDoc(doc(db, "users", this.uid, "projects", id))
.then(() => {
console.log('deleted');
this.fetchUserData(this.uid);
})
.catch(err => console.log(err))
}
},
getters: {
getProjects: (state) => state.projects
}
})
A store is reactive object, the reactivity of store property is disabled at the time when it's accessed in setup function:
const projects = userDataStore.getProjects;
It should be either:
const projects = computed(() => userDataStore.getProjects);
Or:
const { getProjects: projects } = storeToRefs(userDataStore);

Vuejs & Auth0 : I need to reload page to be Authenticated

I'm a beginner in Vue, and I implemented Auth0 to my Web App using Vue3.
My issue: after logging in, my API call to retrieve data get an unauthorized error 403. If I reload the page, everything is working fine.
What should I do to avoid reloading the page to get authenticated directly?
Here are my scripts:
Main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import './index.css'
import dayjs from 'dayjs'
import Datepicker from 'vue3-date-time-picker'
import 'vue3-date-time-picker/dist/main.css'
import { setupAuth } from './auth/index.js'
import authConfig from './auth/config.js'
function callbackRedirect(appState) {
router.push(appState && appState.targetUrl ? appState.targetUrl : '/' );
}
setupAuth(authConfig, callbackRedirect).then((auth) => {
let app = createApp(App).use(router);
app.config.globalProperties.$dayjs = dayjs;
app.component('Datepicker', Datepicker);
app.use(auth).mount('#app');
})
My App.vue script:
<template>
<div v-if="isAuthenticated">
<NavBar />
<router-view/>
</div>
</template>
<script>
import NavBar from './components/NavBar.vue'
export default {
components: { NavBar },
data(){
return {
isAuthenticated: false,
}
},
async mounted(){
await this.getAccessToken()
},
methods: {
async getAccessToken(){
try {
const accessToken = await this.$auth.getTokenSilently()
localStorage.setItem('accessToken', accessToken)
this.isAuthenticated = true
} catch (error) {
console.log('Error occured while trying to retrieve Access Token...', error)
}
},
},
}
</script>
and my Home.vue loading the data:
<template>
<div class="home">
<div class="py-10">
<header>
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<h1 class="text-3xl font-bold leading-tight text-gray-900">Monitoring Dashboard</h1>
</div>
</header>
<main>
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<h3 class="m-5 text-lg leading-6 font-medium text-gray-900">Main KPIs</h3>
<div class="md:grid md:grid-cols-3 md:gap-6">
<div v-for="(item, index) in stats" :key="index" class="md:col-span-1">
<div class="bg-white p-5 border-gray-50 rounded-lg shadow-lg mb-5">
<span class="text-sm font-medium text-gray-500 truncate">{{ item.name }}</span>
<p class="mt-1 text-3xl font-bold text-gray-900">{{ parseFloat(item.stat.toFixed(2)) }}</p>
</div>
</div>
</div>
</div>
</main>
</div>
</div>
</template>
<script>
import _ from 'lodash'
import ProductsService from '../services/products.service'
export default {
name: 'Home',
data(){
return{
user: '',
products: '',
stats: '',
}
},
async mounted(){
await this.readProducts()
await this.buildStats()
},
methods: {
async readProducts(){
let temp = null
try {
temp = await ProductsService.readProducts()
this.products = temp.data
} catch (error) {
console.log('Error: cannot retrieve all products...')
}
},
async buildStats(){
//Nb products
const nbProducts = this.products.length
//Nb offers & Uniq NbRetailers
let nbOffers = 0
let retailers = []
for(let product of this.products){
for(let offer of product.offers){
retailers.push(offer.retailer)
nbOffers += 1
}
}
const nbRetailers = _.uniq(retailers).length
this.stats = [
{ name: 'Number of Retailers', stat: nbRetailers },
{ name: 'Number of Products', stat: nbProducts },
{ name: 'Number of Offers', stat: nbOffers },
]
},
},
watch: {
products: function(){
this.buildStats()
}
}
}
</script>
My ./auth/index.js file:
import createAuth0Client from '#auth0/auth0-spa-js'
import { computed, reactive, watchEffect } from 'vue'
let client
const state = reactive({
loading: true,
isAuthenticated: false,
user: {},
popupOpen: false,
error: null,
})
async function loginWithPopup() {
state.popupOpen = true
try {
await client.loginWithPopup(0)
} catch (e) {
console.error(e)
} finally {
state.popupOpen = false
}
state.user = await client.getUser()
state.isAuthenticated = true
}
async function handleRedirectCallback() {
state.loading = true
try {
await client.handleRedirectCallback()
state.user = await client.getUser()
state.isAuthenticated = true
} catch (e) {
state.error = e
} finally {
state.loading = false
}
}
function loginWithRedirect(o) {
return client.loginWithRedirect(o)
}
function getIdTokenClaims(o) {
return client.getIdTokenClaims(o)
}
function getTokenSilently(o) {
return client.getTokenSilently(o)
}
function getTokenWithPopup(o) {
return client.getTokenWithPopup(o)
}
function logout(o) {
return client.logout(o)
}
export const authPlugin = {
isAuthenticated: computed(() => state.isAuthenticated),
loading: computed(() => state.loading),
user: computed(() => state.user),
getIdTokenClaims,
getTokenSilently,
getTokenWithPopup,
handleRedirectCallback,
loginWithRedirect,
loginWithPopup,
logout,
}
export const routeGuard = (to, from, next) => {
const { isAuthenticated, loading, loginWithRedirect } = authPlugin
const verify = () => {
// If the user is authenticated, continue with the route
if (isAuthenticated.value) {
return next()
}
// Otherwise, log in
loginWithRedirect({ appState: { targetUrl: to.fullPath } })
}
// If loading has already finished, check our auth state using `fn()`
if (!loading.value) {
return verify()
}
// Watch for the loading property to change before we check isAuthenticated
watchEffect(() => {
if (loading.value === false) {
return verify()
}
})
}
export const setupAuth = async (options, callbackRedirect) => {
client = await createAuth0Client({
...options,
})
try {
// If the user is returning to the app after authentication
if (
window.location.search.includes('code=') &&
window.location.search.includes('state=')
) {
// handle the redirect and retrieve tokens
const { appState } = await client.handleRedirectCallback()
// Notify subscribers that the redirect callback has happened, passing the appState
// (useful for retrieving any pre-authentication state)
callbackRedirect(appState)
}
} catch (e) {
state.error = e
} finally {
// Initialize our internal authentication state
state.isAuthenticated = await client.isAuthenticated()
state.user = await client.getUser()
state.loading = false
}
return {
install: (app) => {
app.config.globalProperties.$auth = authPlugin
},
}
}

vuejs user logged out if reload page

Below is the code that I have in my router/index.js
Vue.use(Router)
let router = new Router({
mode: 'history',
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld,
meta: {
guest: true
}
},
{
path: "/login",
name: "login",
component: LoginComponent,
meta: {
guest: true
}
},
{
path: "/secure",
name: "secure",
component: SecureComponent,
meta: {
requiresAuth: true
}
},
{
path: "/kelas",
name: "kelas",
component: KelasComponent,
meta: {
requiresAuth: true
}
}
]
})
router.beforeEach((to, from, next) => {
const record = to.matched.some(record => record.meta.requiresAuth);
console.log("record: ")
console.log(record)
if(record) {
console.log(localStorage.getItem('jwtToken'))
if (localStorage.getItem('jwtToken') == null) {
next({
path: '/login',
params: { nextUrl: to.fullPath }
})
} else {
next()
}
} else if(to.matched.some(record => record.meta.guest)) {
if(localStorage.getItem('jwtToken') == null){
next()
}
else{
next()
}
}else {
next()
}
})
export default router
And in my components/Login.vue I have something like below:
<template>
<section id="login">
<h1>Login</h1>
<form #submit="onSubmit">
<b-field label=""
type="is-warning"
message="Please enter a valid email">
<b-input type="email" name="email" v-model="input.email" placeholder="E-mail"></b-input>
</b-field>
<b-field label=""
type="is-warning"
message="Please enter your password">
<b-input type="password" name="password" v-model="input.password" placeholder="Password"></b-input>
</b-field>
<input type="password" name="password" v-model="input.password" placeholder="Password" />-->
<b-field :message="errors"
type="is-danger"
name="errors"
>
<!--<button type="button" v-on:click="login()" class="button">Login</button>-->
<button type="submit" class="button">Login</button>
</b-field>
</form>
</section>
</template>
<script>
import axios from 'axios'
export default {
name: 'Login',
data () {
return {
input: {
email: "",
password: ""
},
result : "",
errors: []
}
},
methods: {
onSubmit (evt) {
evt.preventDefault()
if(this.input.email != "" && this.input.password != "") {
axios.post('http://localhost:8081/api/auth/login', this.input)
.then(response => {
localStorage.setItem('user',JSON.stringify(response.data.user))
localStorage.setItem('jwtToken', response.data.token)
if (localStorage.getItem('jwtToken') != null){
this.$emit("authenticated", true)
this.$emit('loggedIn')
if(this.$route.params.nextUrl != null){
this.$router.push(this.$route.params.nextUrl)
}
else {
this.$router.push('secure')
}
}
})
.catch(e => {
console.log(e.response)
if(e.response.status === 401) {
this.errors.push("Invalid login")
}else{
this.errors.push(e)
}
})
} else {
this.result = "An email and password must be present"
console.log("An email and password must be present")
}
}
}
}
</script>
My codes above works very well. In secure.vue page, I can click a button which opens up kelas.vue page without any problem. But when I tried to refresh the page secure or kelas, it will push me back to page login.
From doing console.log, I can see that the values for jwttoken and to.matched.some(record => record.meta.requiresAuth); are still there; the only difference is when I do a reload, the from at this line router.beforeEach((to, from, next) => { becomes null.
Is there any way I can make the user to be still logged in after the user do a page reload/refresh? It seems that the 'default' behavior for vue is the user aren't meant to do a page reload/refresh.. or am I missing something here?
My bad.In my app.vue I have the code below which was somehow the culprit that keeps on redirecting me to login on page reload/refresh. Removing the code below fixed my problem.
mounted() {
if(!this.authenticated) {
this.$router.replace({ name: "login" })
}
},
methods: {
setAuthenticated (status) {
this.authenticated = status
},
logout () {
this.authenticated = false
}
}
I guess this is one of the problem when I tried to follow several vue nodejs authentication tutorial at once lol