I would like to implement a simple auth mixin for global authentication inside the application and the routing. The auth mixin has a loggedIn
data which is True or False and two functions to log in and out. The whole application is based on the vue router webpack template. The problem is that the loggedIn
state will not be saved. So when I go to the Login.vue and login, loggedIn
will be set to true, but when I go to the Login.vue component again the checkStatus function will log loggedIn
as false
again.
How can I
This is my mixin:
Auth.js
export default {
data() {
return {
loggedIn: false
}
},
methods: {
logIn(user,password) {
return new Promise((resolve, reject) => {
console.log("Logging in ", user, password);
this.loggedIn = true;
resolve()
})
},
logOut(){
return new Promis ((resolve, reject) => {
console.log("Logging out");
this.loggedIn = false;
resolve();
})
}
}
};
main.js
import Vue from 'vue'
import App from './App'
import router from './router'
import Utils from "./mixins/Utils"
import Auth from "./mixins/Auth"
// Load mixins
Vue.mixin(Auth);
Vue.mixin(Utils);
// This part redirects to login page when authentication is needed
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth) && this.loggedIn) {
next({ path: '/login', query: { redirect: to.fullPath }});
} else {
next();
}
});
Login.vue
<template>
<div>
<form class="form-signin">
<h1 class="mb-3">Please sign in</h1>
<label for="inputEmail" class="sr-only">Email address</label>
<input type="email" id="inputEmail" v-model="email" class="form-control" placeholder="Email address" required autofocus>
<label for="inputPassword" class="sr-only">Password</label>
<input type="password" id="inputPassword" class="form-control" placeholder="Password" required v-model="password">
<div class="checkbox mb-3">
<label>
<input type="checkbox" value="remember-me"> Remember me
</label>
</div>
<button class="btn btn-lg btn-primary btn-block" type="submit" v-on:click="checkCredentials">Sign in</button>
</form>
<div class="mb-3" style="text-align: center">
<label>
<router-link to="/signup">Not registerd yet? Sign up!</router-link>
</label>
</div>
<notifications position="bottom center" group="notifications" />
</div>
</template>
<script>
export default {
name: 'Login',
methods: {
checkCredentials(event) {
event.preventDefault();
if (this.email.length <= 0 || !this.email) {
this.notify("Enter email", "warn")
return;
}
if (this.password.length <= 0 || !this.password) {
this.notify("Enter password", "warn");
return;
}
this.performLogin(this.email, this.password);
},
performLogin(mail, password) {
let x = this;
this.logIn(mail, password)
.then(function (result) {
x.notify("Logged in as " + mail, "success");
if (x.loggedIn) {
console.log("[LOG] redirecting");
x.$router.push(x.$route.query.redirect || '/');
}
})
.catch(function (error) {
document.cookie = "Test";
x.notify("Error loggin in (" + error + ")", "error");
})
},
checkStatus() {
this.$log.info("Checking status", this.loggedIn)
if (this.loggedIn) {
this.$router.push(this.$route.query.redirect || "/");
}
}
},
data() {
return {
email: "",
password: ""
}
},
created() {
this.checkStatus()
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.form-signin {
width: 100%;
max-width: 330px;
padding: 15px;
margin: auto;
}
.form-signin .checkbox {
font-weight: 400;
}
.form-signin .form-control {
position: relative;
box-sizing: border-box;
height: auto;
padding: 10px;
font-size: 16px;
}
.form-signin .form-control:focus {
z-index: 2;
}
.form-signin input[type="email"] {
margin-bottom: -1px;
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
}
.form-signin input[type="password"] {
margin-bottom: 10px;
border-top-left-radius: 0;
border-top-right-radius: 0;
}
</style>
The problem is that the loggedIn state will not be saved.
Exactly, Mixins are not meant for managing the state they are supposed to be used for functions/methods that needs to be reused in your components, to maintain the state you'd need a state management system and Vue provides one, it's called Vuex.
With Vuex you could define an initial state, in your case whether the user has logged in or not, I'd recommend you to go through the Vuex Docs once
Here's a short and simple example of how it will solve your problem,
const store = new Vuex.Store({
state: {
loggedIn: false
},
mutations: {
logInUser (state) {
state.loggedIn = true
}
}
})
/* Pass the store to your Vue App */
const app = new Vue({
el: '#app',
// this will inject the store instance to all child components.
store,
components: { App },
..........
Now this state will be available throughout your components and won't change unless you commit a change from somewhere manually.
Login.vue
this.$store.commit('logInUser', true)
someOtherComp.vue
console.log(this.$store.state.loggedIn) // true