Protect a vue route with multiple guards - javascript

I have a vue router like this:
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
function guard (to, from, next) {
if (localStorage.getItem('jwt')) {
next()
} else {
next('/login')
}
}
function admin (to, from, next) {
if (localStorage.getItem('admin') && localStorage.getItem('admin') !== 'false' && localStorage.getItem('jwt')) {
next()
} else {
next('/noadmin')
}
}
export default new Router({
mode: 'history',
routes: [
{
path: '/',
name: 'home',
beforeEnter: guard,
meta: { layout: 'default' },
component: () => import('#/components/dashboard.vue')
},
{
path: '/datacollector',
name: 'datacollector',
beforeEnter: guard,
meta: { layout: 'default' },
component: () => import('#/components/datacollector.vue')
},
{
path: '/licensing',
beforeEnter: admin,
name: 'licensing',
component: () => import('#/components/licensing.vue')
},
{
path: '*',
name: '404',
component: require('#/pages/404.vue').default
}
]
})
My problem now is the following, if there is an entry localStorage.getItem('datacollector') it should only point to the path /datacollector and /logout. So when he logs in, the login page throws him to the path /datacollector. But he should also be able to call logout. For the other users, it should be that they are allowed to call everything. How do I adjust the function guard, no matter what I try I always end up with a loop. Thank you.

Assuming you want to throw the user to /datacollector route from any route, if there is an entry for localStorage.getItem('datacollector'), except for /logout route.
You can simply check for to.path and redirect the user accordingly:
function guard (to, from, next) {
if (localStorage.getItem('jwt')) {
if (localStorage.getItem('datacollector')) {
if (to.path != '/datacollector' && to.path != '/logout'){
next('/datacollector');
} else {
next();
}
} else {
next();
}
} else {
next('/login')
}
}

Related

Redirection based on user type - vue router

I am a beginner in vue and I need your help please. I am creating an application where the login is connected to firebase. I would like to use vue-router to redirect a user to a particular page. When a person logs in whose user.role = "admin" it should be redirected to "/admin". Every other logged person to "/" and non-logged in people are redirected to "/login" page.
Here are parts of my code:
main.js
router.beforeEach((to, from, next) => {
const currentUser = firebase.auth().currentUser;
const requiresAuth = to.meta.requiresAuth;
if (requiresAuth && !currentUser){ next({ name: 'Login' })}
else if (!requiresAuth && currentUser) {next({name: 'Dashboard'}), console.log(currentUser)}
else next();
});
authStore.js
const actions = {
logIn({ dispatch,commit,rootGetters }){
firebase.auth().onAuthStateChanged(async (user) => {
if (user) {
commit('SET_USER', user);
var uid = user.uid;
db.collection('users').doc(uid)
.get()
.then((doc)=>{
commit('gutscheinStore/SET_USER_ROLE', doc.data().role, {root:true})
commit('gutscheinStore/SET_USER_STANDORT_ID', doc.data().standortID, {root: true})
commit('gutscheinStore/SET_USER_BETREIBER_ID', doc.data().betreiberID, {root: true})
//console.log(rootGetters['gutscheinStore/getUserRole'])
})
router.push('/')
} else {
console.log("No entry without login")
}
})
},
index.js in router
const routes = [
{
path: '/',
name: 'Dashboard',
component: Dashboard,
meta: {
requiresAuth: true,
}
},
{
path: '/login',
name: 'Login',
component: Login
},
{
path: '/admin',
name:'AdminDashboard',
component: AdminDashboard,
meta: {
requiresAuth: true,
}
In authStore.js where you currently have the line router.push("/"):
const actions = {
...
// snipped for clarity
router.push('/')
} else {
console.log("No entry without login")
}
})
},
You could instead change this as follows:
const actions = {
...
// snipped for clarity
if(user.role === "admin") {
router.push("/admin")
} else {
router.push("/")
}
} else {
// router.push("/login")
router.go()
}
})
},

Vue: How to use Per-Route Guard with Vuex getter?

Similar to the way that we handle with isAuthenticate function to check if user has properly authenticated, I'm trying to inspect in my store.
const state = {
cliente: []
};
const getters = {
//Verificar Regra
CHECK_CLIENTE_STATE: (state) => {
return state.cliente
}
}
const actions = {
FETCH_DADOS({ commit }, obj) {
return fetch(`http://localhost:3030/pessoas/informacao/${obj['data']}`)
.then(response => response.json())
.then(data => commit('SetCliente', data))
.catch(error => console.log(`Fetch: ${error}`))
}
}
const mutations = {
SetCliente(state, cliente) {
state.cliente = cliente
}
}
login page,
methods:{
fetch(){
this.$store.dispatch("FETCH_DADOS",{'data':'12345'})
this.$router.push('/')
}
}
At the first fetch click, I inspect Vuex, apparently it is working.
Routes:
const routes = [{
path: '/',
beforeEnter: (to, from, next) => {
if (store.getters.CHECK_CLIENTE_STATE == '') {
next('/login')
}
next();
},
component: () =>
import ('../views/Home')
},
{
path: '/login',
component: () =>
import ('../views/Login')
}
]
Well, in console.log at the first fetch click, I receive this error, but in vuex as shown above, the store is filled.
Uncaught (in promise) Error: Redirected when going from "/login" to
"/" via a navigation guard.
Why just in the second click is it redirected to home, not in the first?
Updating
Trying a new approach in router.js
path: '/',
beforeEnter: (to, from, next) => {
console.log(!store.getters.CHECK_CLIENTE_STATE.length)
if (!store.getters.CHECK_CLIENTE_STATE.length) {
next('/login')
}
next();
},
component: () =>
import ('../views/Home')
But again, the first fetch is TRUE and the second FALSE, in the second I'm redirected to /home
The router is being directed before the data is loaded. Wait for it:
methods:{
async fetch(){
await this.$store.dispatch("FETCH_DADOS",{'data':'12345'})
this.$router.push('/')
}
}

Have to click login button twice; Using vue-router and firebase authentication

I have setup up a router guard so when I login instead of my router pushing it to the dashboard the split second time it requires firebase to authenticate it thinks im not logged in and I have to wait and click the login button again.
Is there any way to wait for it to log in then the router pushes me to the dashboard.
Im new to this any help would be appreciated.
//routes
export const routes = [
{
path: "/adduser",
component: AddUser,
meta: {
requiresAuth: true
}
},
{
name: "details",
path: "/details/:id",
component: User,
meta: {
requiresAuth: true
}
},
{
path: "/register",
component: Register,
meta: {
requiresGuest: true
}
},
{
path: "/login",
component: Login,
meta: {
requiresGuest: true
}
},
{
path: "/dashboard",
component: Dashboard,
meta: {
requiresAuth: true
}
},
{
path: "/",
component: Dashboard,
meta: {
requiresAuth: true
}
},
{
name: "editUser",
path: "edituser/:id",
component: EditUser,
meta: {
requiresAuth: true
}
}
];
//the login function
emailLogin(email, password) {
firebase
.auth()
.signInWithEmailAndPassword(email, password)
.then(this.$router.push("/dashboard"))
.then(() => {
this.$store.dispatch("auth/login");
});
}
//the router guard
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
if (!firebase.auth().currentUser) {
next({
path: "/login",
query: {
redirect: to.fullPath
}
});
} else {
next();
}
} else if (to.matched.some(record => record.meta.requiresGuest)) {
if (firebase.auth().currentUser) {
next({
path: "/"
});
} else {
next();
}
} else {
next();
}
});
inside the then(this.$router.push("/dashboard")) the push gives a promise which should be returned to an arrow function.
So the new login function would be:
emailLogin(email, password) {
firebase
.auth()
.signInWithEmailAndPassword(email, password)
.then(() => {
this.$router.push("/dashboard");
})
.then(() => {
this.$store.dispatch("auth/login");
});
}

How to use vue-resource in navigation guard

I'm trying to use vue-resource inside my router to get info about the user by token to protect some routes:
router/index.js:
const router = new Router({
mode: 'history',
linkExactActiveClass: 'is-active',
routes: [
{
path: '/login',
name: 'Login',
component: Login
},
{
path: '/board',
name: 'Board',
component: Board,
meta: {
requiresAuth: true
}
}
]
})
router.beforeEach((to, from, next) => {
// check if rout requires auth
if (to.matched.some(rec => rec.meta.requiresAuth)) {
const token = localStorage.getItem('user-token')
if (token == null) {
next({ name: 'Login' })
}
else {
this.$http.get('/rest-auth/user/', {headers: {"Authorization": "Token " + token}})
.then(response => { next() }, response => { next({ name: 'Login' }) });
}
}
else {
next()
}
})
But I'm getting error when I'm trying to log in: TypeError: Cannot read property 'get' of undefined, so I've tried to solve it like this to get access to vm instance:
router.beforeEach((to, from, next) => {
// check if rout requires auth
if (to.matched.some(rec => rec.meta.requiresAuth)) {
const token = localStorage.getItem('user-token')
if (token == null) {
next({ name: 'Login' })
}
else {
next(vm => {
vm.$http.get('/rest-auth/user/', {headers: {"Authorization": "Token " + token}})
.then(response => { next() }, response => { next({ name: 'Login' }) });
})
}
}
else {
next()
}
})
But it's not working also, so maybe i need to switch to axios to do it?
I'm pretty sure you need to import vue-resource from 'vue-resource'

How to stop component-loading and redirect in Vue?

I have a component which is not to be accessed by non-logged-in user. I implemented this logic into the beforeCreate hook. Problem is that this doesn't stop the component from continuing in loading, which I want it to.
This is my code:
<script>
export default {
beforeCreate: function () {
if (this.$root.auth.user === null) {
this.$router.push({ name: 'auth.login' })
}
},
mounted: function () {
// some code that SHOULD NOT be processed
// if the user isn't authenticated
}
}
</script>
What am I doing wrong?
You should move your beforeCreate function to the router itself.
Here's my Auth catch
router.beforeEach(
(to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
// if route requires auth and user isn't authenticated
if (!store.state.Authentication.authenticated) {
let query = to.fullPath.match(/^\/$/) ? {} : { redirect: to.fullPath }
next(
{
path: '/login',
query: query
}
)
return
}
}
next()
}
)
It allows me to use my routes definition to handle auth and guest placements.
{
path: '/',
component: load('Template'),
children: [
{ path: '', component: load('Dashboard'), name: 'Dashboard' }
],
meta: { requiresAuth: true }
},
{
path: '/login',
component: load('Authentication/Login'),
name: 'login'
},
By having it in the router it's called before the components are initialized by Vue, this will stop processing of any component level events.

Categories