I’m using this ssr boilerplate for my app, https://github.com/vuejs/vue-hackernews-2.0
I don’t know how to implement logic for checking is user authenticated for each user’s page request, I’m using cookies for storing user's token
I looked that router can handle request before render component:
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
// this route requires auth, check if logged in
// if not, redirect to login page.
// isLoggedIn()
// .then(response => response.json())
// .then(json => {
// console.log(json[0])
// next()
// })
// .catch(error => {
// console.log(error)
// next()
// })
const x = true
if (!x) {
next({
path: '/signin',
query: { redirect: to.fullPath }
})
} else {
next()
}
} else {
next() // make sure to always call next()!
}
})
return router
}
But here is problem, router starting to use this code in client-side and in server-side, which in my case a little bit incorrect.
How to send request for is user authenticated only once, or in client-side or in server-side?
Answering on my issue, next approach - is what I searched, this vue router middleware will check user, before sending other requests(in my components methods like asyncData), then put user's info into store:
// router/index.js
export function createRouter (cookies) {
const router = new Router({ ... })
router.beforeEach((to, from, next) => {
// this route requires auth, check if logged in
// if not, redirect to login page.
if (to.matched.some(record => record.meta.requiresAuth)) {
if (router.app.$store) {
router.app.$store
.dispatch('FETCH_CURRENT_USER', cookies)
.then(next)
.catch(() => next('/signin'))
} else {
next()
}
} else {
next()
}
return router
}
// store/actions.js
export default {
FETCH_CURRENT_USER: ({ commit }, cookie) => {
const values = {
credentials: 'include',
headers: {
'Content-Type': 'application/json',
Origin: FRONTEND_HOST,
Cookie: cookie
}
}
return fetch(`${API_HOST}/api/v1/users/me`, values)
.then(handleStatus)
.then(handleJSON)
.then(json => commit('SET_CURRENT_USER', json))
}
}
Related
I have the needings to use firebase auth with vue router.
I have this simple guard, but I've noticed that sometimes the users will see for a while the pages also if they are not logged.
router.beforeEach( async (to, from) => {
onAuthStateChanged( getAuth(app), (user) => {
console.log(user, to.meta.requireAuth)
if( to.meta.requireAuth && !user ) {
return {
name: 'Signin'
}
}
})
})
I also have this kind of control inside my components, but I'm looking for something global to use to prevent unregistered users to see the app.
Any suggestion?
You can wrap the onAuthStateChanged in a Promise and make your before each an async function.
// in some global file
export async function getCurrentUser(): Promise<User | null> {
return new Promise((resolve, reject) => {
const unsubscribe = auth.onAuthStateChanged((user) => {
unsubscribe();
resolve(user);
}, reject);
});
}
// your router file
router.beforeEach(async (to, from, next) => {
if (to.matched.some((record) => record.meta.publicAccess)) {
next();
} else {
const currentUser = await getCurrentUser();
if (currentUser) {
next();
} else {
next({ name: "Login" });
}
}
});
// Your route object
{
name: "Login",
path: "/login",
component: () => import("#/views/authentication/Login.vue"),
}
Need to do something like middleware, need to check if the user has a token, then allow the transition
router.beforeEach((to, from, next) => {
const accessNeed = ['Dashboard',]
if (localStorage.getItem("token")){
if (!accessNeed.includes(to.name)) {
next({ name: 'Home' })
}else{
next()
}
}else{
next()
}
})
You are either using Nuxt, or just the Vue SSR package. So you have to make sure, the code gets executed only on client:
router.beforeEach((to, from, next) => {
if (!process.client) {
next()
return
}
const accessNeed = ['Dashboard']
if (window && window.localStorage.getItem("token")){
if (!accessNeed.includes(to.name)) {
next({ name: 'Home' })
} else{
next()
}
}
next()
})
Guys i don't know why im get this error when i try to login, console error after login is made:
Error: Redirected when going from "/pages/login" to "/dashboard"
via a navigation guard.
Im trying when i hit login to redirect me to /dashboard page after the validation is made but when i hit login it does nothing no redirect, and if i hit again the login button the redirect is made on dashboard page. Any solutions? Thanks!
loginJWT ({ commit }, payload) {
return new Promise((resolve, reject) => {
jwt.login(payload.email, payload.password)
.then(response => {
console.log(response.data)
// If there's user data in response
if (response.data.userDetails) {
// Navigate User to homepage
router.push(router.currentRoute.query.to || '/') // <- Here is the redirect after login
// Set accessToken
localStorage.setItem('accessToken', response.data.accessToken)
// Update user details
commit('UPDATE_USER_INFO', response.data.userDetails, {root: true})
// Set bearer token in axios
commit('SET_BEARER', response.data.accessToken)
resolve(response)
} else {
reject({message: 'Wrong Email or Password'})
}
})
.catch(error => { reject(error) })
})
}
In router js:
{
path: '/dashboard',
name: 'dashboard',
component: () => import('./views/Dashboard.vue'),
meta: {
rule: 'editor',
authRequired: false
},
beforeEnter: (to, from, next) => {
guard(to, from, next)
}
}
And the guard code that validate the token after each route:
const guard = function (to, from, next) {
// check for valid auth token
const token = localStorage.getItem('accessToken')
axios.post('http://localhost:8081/api/users/checkAuthToken', {tokn: token})
.then(function (response) {
if (response.status === 200) {
next()
}
}).catch(function (error) {
if (error.response && error.response.status === 401) {
alert('access neautorizat')
next('/pages/login')
localStorage.removeItem('userInfo')
localStorage.removeItem('accessToken')
}
})
}
beforeEach code:
router.beforeEach((to, from, next) => {
const publicPages = [
'/pages/login',
'/pages/register',
'/pages/forgot-password',
'/pages/comingsoon',
'/pages/error-404',
'/pages/error-500',
'/pages/not-authorized',
'/pages/maintenance',
'/callback'
]
const authRequired = !publicPages.includes(to.path)
const loggedIn = localStorage.getItem('accessToken')
if (authRequired && !loggedIn) {
return next('/pages/login')
}
return next()
})
First Set accessToken and Last Navigate User to homepage
I'm working with vue and django rest framework, and what I want to do is validate if I don't have a token in my localStorage (not login) redirect to login page.
Here my component code in my login.vue:
<script>
import axios from 'axios'
import swal from 'sweetalert'
export default {
data () {
return {
username: '',
password: '',
token: localStorage.getItem('user-token') || null
}
},
methods: {
login() {
axios.post('http://localhost:8000/auth/', {
username: this.username,
password: this.password,
})
.then(resp => {
this.token = resp.data.token;
localStorage.setItem('user-token', resp.data.token)
this.$router.push('/atentusianos')
})
.catch(err => {
localStorage.removeItem('user-token')
swal("Credenciales Incorrectas", "", "error")
})
}
}
}
</script>
If the authentication is correct, i get my token from my localStorage like this:
...
methods: {
getAtentusianos(){
let axiosConfig = {
headers: {
'Authorization': 'Token ' + this.token
}
}
const path = 'http://localhost:8000/atentusianos/'
axios.get(path, axiosConfig).then((response) => {
this.atentusianos = response.data
})
.catch((error) => {
console.log(error)
})
}
},
created(){
let token;
this.token = TokenService.getToken()
this.getAtentusianos()
}...
I need help please...
You can do this in your Vue Router beforeEach guard. This runs on every route before directing to the requested page, including on a new page load or refresh, so it's ideal for handling this type of logged in check.
router.beforeEach((to, from, next) => {
const token = localStorage.getItem('user-token')
// If logged in, or going to the Login page.
if (token || to.name === 'Login') {
// Continue to page.
next()
} else {
// Not logged in, redirect to login.
next({name: 'Login'})
}
}
});
Note: this code assumes your login route name is Login, so you can update that accordingly.
I also recommend using VueX to get and store your auth token, and your default value for the token in your store can be from local storage or a cookie. That just makes it more efficient, checking the Vuex store value instead of getting it from local storage or the cookie every time.
Vue Router navigation guards: https://router.vuejs.org/guide/advanced/navigation-guards.html
I have a simple vue app where I'm trying to add simple authentication. Inside my login.vue, I use axios to authenticate the user via ajax and store the token returned by the api in the store then redirect to a new page (ex: dashboard.vue).
The problem is that the token is saved but the view is not updated, can't call router.push() ...
Any ideas why isn't it working ? Thanks
Login.vue
methods: {
authenticate () {
var dataLogin = {
email: this.login,
password: this.password
}
var headers = { headers: { 'Content-type': 'application/json', 'Accept': 'application/json' } }
axios.post(config.apiUrl, dataLogin, headers)
.then(response => {
this.$store.dispatch('login', response.data).then(() => {
// if there is no error go to home page
if (!this.$store.getters.error) {
this.$router.push('/')
}
})
})
.catch(error => {
this.errorMessage = error.response.data.message
this.authError = true
})
}
}
The store function just save the token with localStorage
const actions = {
login (context, data) {
context.commit('authenticate', data)
}
}
const mutations = {
authenticate (state, data) {
localStorage.setItem('user-access_token', data.access_token)
}
}
You are calling a then() handler when you dispatch the action.
But your action does not return a promise.
So return a promise in your action as follows:
const actions = {
login (context, data) {
return new Promise((resolve, reject) => {
context.commit('authenticate', data)
resolve()
})
}
}
Also chain your promises for better readability
axios.post(config.apiUrl, dataLogin, headers)
.then(response => {
return this.$store.dispatch('login', response.data)
}).then(() => {
// if there is no error go to home page
if (!this.$store.getters.error) {
this.$router.push('/')
}
})
.catch(error => {
this.errorMessage = error.response.data.message
this.authError = true
})