I am trying to send a JWT token value from the Login.vue component and to validate it in the router/index.js before I redirect the user for the next page.
Login.vue:
<script>
import axios from "axios";
export default {
name: "Login",
methods: {
login() {
let userDetails = {
'Username' : this.email,
'Password' : this.password
}
axios
.post('https://localhost:44349/api/Token/CreateToken',userDetails)
.then((response) => {
this.token = response.data.token
this.$router.push({
name:'Books',
params:{token:this.token}}) // <--- send Token
})
.catch((error) => {
console.log(error)
});
}
}
};
</script>
router/index.js
const router = new Router({
routes: [
{
path: '/books',
name: 'books',
component: Books,
props: true,
meta: {
requiresAuth: true
}
},
{
path: '/login',
name: 'Login',
component: Login
}
]
});
router.beforeEach((to, form, next) => {
if (to.matched.some(rec => rec.meta.requiresAuth)) {
let isTokenValid= ??; // how to get the token?
if (isTokenValid) {
next();
}
else {
next({ name: 'Login' });
}
}
});
export default router
I used localstorage to store token. Alternatively you can use vuex for storage, do follow this Authentication using Vuex
.then((response) => {
this.token = response.data.token
localStorage.setItem('user-token', this.token);
this.$router.push({
name:'Books',
}) // <--- send Token
}).catch(){
localStorage.removeItem('user-token');
}
Related
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()
}
})
},
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");
});
}
After a new project is created, I'd like to route the user to another page so they can add more information to the project.
This is working:
createProject() {
ProjectService.createProject(this.project)
.then(response => {
this.$router.push({
name: "project-update",
params: { id: response.data.data.id }
});
})
}
I'd like to use vuex to handle all this, but this is not working.
createProject() {
this.$store
.dispatch("project/postProject", this.project)
.then(response => {
this.$router.push({
name: "project-update",
params: { id: response.data.data.id }
});
})
.catch(() => {});
}
The error I'm getting is: "state.projects.push is not a function"
This is my postProject action in Vuex:
postProject({ commit, dispatch }, project) {
return ProjectService.createProject(project)
.then(() => {
commit('ADD_PROJECT', project);
const notification = {
type: 'success',
message: 'Your project has been created!'
};
dispatch('notification/add', notification, { root: true });
})
.catch(error => {
const notification = {
type: 'error',
message: 'There was a problem creating your project: ' + error.message
};
dispatch('notification/add', notification, { root: true });
throw error;
});
}
Looks like the context of 'this' is not reaching the router or the push function therein. How can I access the router and route to that next page?
What you can do is import your router module into your vuex module like so:
import {router} from "../main.js"
// or
import router from '../router'
export default {
actions: {
createProject () {
this.$store
.dispatch("project/postProject", this.project)
.then(response => {
router.push({
name: "project-update",
params: { id: response.data.data.id }
})
})
.catch(() => { })
}
}
}
I have a same issue but I solved by doing this:
this.$router.replace("/");
Having issue in vuex and nuxt store by using this : this.$router.push("/");
I am using passport-jwt strategy to protect auth users in my app, once I login I am generating a jwt-token now I want to protect my welcome page rout so that user cannot open it without login
So when I login I am creating jwt-token with payload like this
my user.js file
const payload = { email: rows[0].email } // jwy payload
console.log('PAYLOAD')
console.log(payload)
jwt.sign(
payload,
key.secretOrKey, { expiresIn: 3600 },
(err, token) => {
res.json({
success: true,
token: 'Bearer ' + token,
email
})
})
Now in my passport.js I am doing like this
const opts = {};
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = keys.secretOrKey;
passport.use(new JwtStrategy(opts, (jwt_payload, done) => {
let payLoadEmail = jwt_payload.email //payload data what I have passed in creating jwt
console.log("payload email :" + payLoadEmail)
User.fetchLogedInUser(payLoadEmail)
.then(([rows]) => {
if (rows.length > 0) {
return done(null, rows[0].email) // returning data what I need
}
return done(null, false)
})
.catch(err => console.log(err))
}));
Both are working fine.
Now I want to protect my welcome rout so in my router.js file
const express = require('express');
const router = express.Router();
const passport = require('passport')
const UsersCtrl = require('../controllers/users');
router.use('/login', UsersCtrl.login)
router.use('/welcome',passport.authenticate('jwt',{session:false}))
router.use('/logout', UsersCtrl.logout)
module.exports = router;
suppose user types localhost:8080/welcome without login then I want to protect it
So in my store.js file when user logs in I am doing this on login click and I have made a method getAuthUser. I don't know how to I pass this config to protect my welcome file
Here is my full store.js code
import axios from 'axios'
import jwt from 'jsonwebtoken'
function checkTokenValidity(token) { // token validity
if (token) {
const decodedToken = jwt.decode(token)
return decodedToken && (decodedToken.exp * 1000) > new Date().getTime()
}
return false
}
export default {
namespaced: true,
state: {
user: null,
isAuthResolved: false // this I am calling on my login page i am confused where should I call this or not to call this
},
getters: {
authUser(state) {
return state.user
},
isAuthenticated(state) {
return !!state.user
}
},
actions: {
loginWithCredentials({ commit }, userDate) {
return axios.post('/api/v1/users/login', userDate)
.then(res => {
const user = res.data
console.log(user.email)
localStorage.setItem('jwt-token', user.token)
commit('setAuthUser', user)
})
},
logout({ commit }) {
return new Promise((resolve, reject) => {
localStorage.removeItem('jwt-token')
commit('setAuthUser', null)
resolve(true)
})
},
getAuthUser({ commit, getters }) {
const authUser = getters['authUser']
const token = localStorage.getItem('jwt-token')
const isTokenValid = checkTokenValidity(token)
if (authUser && isTokenValid) {
return Promise.resolve(authUser)
}
const config = { // here what to do with this how can I pass this to protect my route
headers: {
'cache-control': 'no-cache',
'Authorization': token
}
}
}
},
mutations: {
setAuthUser(state, user) {
return state.user = user
},
setAuthState(state, authState) {
return state.isAuthResolved = authState
}
}
In my route.js vue file
import Vue from 'vue'
import Router from 'vue-router'
import store from './store'
Vue.use(Router)
const router = new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [{
path: '/welcome',
name: 'welcome',
meta: { onlyAuthUser: true },
component: () =>
import ('./views/Welcome.vue'),
}, ]
})
router.beforeEach((to, from, next) => {
store.dispatch('auth/getAuthUser')
.then((authUser) => {
const isAuthenticated = store.getters['auth/isAuthenticated']
if (to.meta.onlyAuthUser) {
if (isAuthenticated) {
next()
} else {
next({ name: 'PageNotAuthenticated' })
}
} else if (to.meta.onlyGuestUser) {
if (isAuthenticated) {
next({ name: 'welcome' })
} else {
next()
}
} else {
next()
}
})
})
export default router
My main problem is I want to protect routes and make the user authenticated using jwt and passport I am getting jwt once I login and want to check once my protected rout is access with out login for backend.
In front end (vue.js) I my store file in action> getAuthUsers I don't know how to pass config to other routes like my welcome.
Not sure if I understood your question entirely because you seem to be implementing route access correctly. You simply need to add routes as an array while the rest of your code remains the same.
const router = new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [{
path: '/welcome',
name: 'welcome',
meta: { onlyAuthUser: true },
component: () =>
import ('./views/Welcome.vue'),
},
{
path: '/login',
name: 'Login',
meta: { onlyGuesUser: true },
component: () =>
import ('./views/Login.vue'),
}]
})
For using Authentication: Bearer xxxxxxxx you can modify your axios code to directly use required headers instead of passing it through routes every time. Make a new folder called services and a file called base-api. You can obviously name it however you like, but this is my setup.
import axios from 'axios';
export default () => {
let headers = {
'cache-control': 'no-cache'
};
let accessToken = localStorage.getItem('jwt-token');
if (accessToken && accessToken !== '') {
headers.Authorization = accessToken;
};
return axios.create({
baseURL: 'SECRET_URL_',
headers: headers
});
}
Import this file in your store.js. Replace import axios from 'axios' with import axios from '#src/services/base-api.js. As the file is returning an axios instance you need to access it as axios(). Which means you function would be
return axios().post('/api/v1/users/login', userDate)
.then(res => {
// do whatever
})
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'