I would like to know how to use Axios in vueRouter in beforeEach()
i did like that :
router.beforeEach((to, from, next) => {
axios.$http.get('http://localhost:3000/me', {
headers: {
'x-access-token': $cookies.get('user_session') //the token is a variable which holds the token
}
})
.then(response => {
if (response.status == "200") {
console.log('tet3');
}
}, response => {
this.$cookies.remove("user_session");
this.$router.push('/')
//window.location.href = "/";
console.log('erreur', response)
})
if (to.matched.some(record => record.meta.requiresAuth)) {
if (!$cookies.get('user_session')) {
next({
path: '/login',
params: {nextUrl: to.fullPath}
})
} else {
let user = JSON.parse(localStorage.getItem('user'))
if (to.matched.some(record => record.meta.is_admin)) {
if (user.is_admin == 1) {
next()
}
else {
next({name: 'userboard'})
}
}
else {
next()
}
}
} else if (to.matched.some(record => record.meta.guest)) {
if ($cookies.get('user_session') == null) {
next()
}
else {
next({name: 'userboard'})
}
} else {
next()
}
})
and the result is an error :
axios is not defined
I can't use 'this', beceause 'this' is VueRouter
Do you know how to do ?
Thank you
You have to import it:
import axios from 'axios'
const http = axios.create({
baseURL: 'http://localhost:3000/',
})
...
http.get('me', {
headers: {
'x-access-token': $cookies.get('user_session') //the token is a variable which holds the token
}
})
.then(response => {
if (response.status == "200") {
console.log('tet3');
}
}, response => {
this.$cookies.remove("user_session");
this.$router.push('/')
//window.location.href = "/";
console.log('erreur', response)
})
...
Related
This is my refresh token plugin
refresh_token.js
const axiosOnResponseErrorPlugin = ({ app, $axios, store }) => {
$axios.onResponseError(err => {
const code = parseInt(err.response && err.response.status)
let originalRequest = err.config
if (code === 401) {
originalRequest.__isRetryRequest = true
const refreshToken = store.state.auth.refresh_token ? store.state.auth.refresh_token : null
if (refreshToken) {
return new Promise((resolve, reject) => {
$axios.post('refresh-token/', {
refresh: refreshToken
})
.then((response) => {
if (response.status === 200) {
let auth = response.data
err.response.config.headers['Authorization'] = `${auth.access}`
}
resolve(response)
})
.catch(e => {
// should jump here after facing error from request
reject(e)
})
})
.then((res) => {
return $axios(originalRequest)
})
.catch(e => {
app.router.push('/')
})
}
}
})
}
export default axiosOnResponseErrorPlugin
My problem is, if refresh token is not expired then it's working fine, but if it is expired then it should redirect to a page which is not doing right now. I couldn't find any way to redirect/push to another router after expiration.
Have any suggestion ?
Here is my solution about this situation ..You have to check your original request also. and for that it will create a loop ..if some how refresh token is failed .So check it with your refresh token URL.
$axios.interceptors.response.use(
response => {
return response;
},
function(error) {
const originalRequest = error.config;
if (error.response.status === 401 && originalRequest.url === "accounts/refresh-token/") {
store.dispatch("clearUserData")
return Promise.reject(error)
}
if (error.response.status === 401 && !originalRequest._retry) {
console.log('originalRequest ', originalRequest)
originalRequest._retry = true;
const refreshToken = localStorage.getItem("UserRefreshToken");
return store.dispatch("refreshToken")
.then(res => {
$axios.defaults.headers.common[
"Authorization"
] = localStorage.getItem("UserToken");
return $axios(originalRequest);
})
}
return Promise.reject(error);
}
);
Here is the complete solution of this question
refresh_token.js
const axiosOnResponseErrorPlugin = ({ app, $axios, store }) => {
$axios.onResponseError(err => {
const code = parseInt(err.response && err.response.status)
let originalRequest = err.config
let explode = originalRequest.url.split("/") // i split the original URL to fulfill my condition
if (code === 401 && explode[explode.length - 2] === "refresh-token") {
app.router.push('/')
}
if (code === 401 && !originalRequest._retry) {
originalRequest._retry = true
const refreshToken = store.state.auth.refresh_token ? store.state.auth.refresh_token : null
if (refreshToken) {
return new Promise((resolve, reject) => {
$axios.post('refresh-token/', {
refresh: refreshToken
})
.then((response) => {
if (response.status === 200) {
let auth = response.data
err.response.config.headers['Authorization'] = `${auth.access}`
}
resolve(response)
})
.catch(e => {
// should jump here after facing error from request
reject(e)
})
})
.then((res) => {
return $axios(originalRequest)
})
.catch(e => {
app.router.push('/')
})
}
}
})
}
export default axiosOnResponseErrorPlugin
I have loaded all permissions when the sidebar is loading after login and getters are updated. I can access all permissions from the sidebar component.
Now I want to access all permissions in my middleware. Is it possible? What to do?
Please give a suggestion.
Here is my permission store:
const state = {
permissions: [],
user: [],
}
const getters = {
getPermissions: state => state.permissions,
getUserInfo: state => state.user,
}
const actions = {
userPermission({commit}, data) {
if (data != null) {
axios.get("/api/auth/user", {params: { token: data.token}})
.then(res => {
const per = res.data.data.permissions;
commit("setPermissions", per);
// console.log(res.data.data.permissions);
})
.catch(err => {
console.log(err);
});
}
},
userInfo({commit}, data) {
if (data != null) {
axios.get("/api/auth/user", {params: { token: data.token}})
.then(res => {
const info = res.data.data.user;
commit("setUserInfo", info);
// console.log(res.data.data.user);
})
.catch(err => {
console.log(err);
});
}
},
}
const mutations = {
setPermissions(state, data) {
state.permissions = data;
},
setUserInfo(state, data) {
state.user = data;
}
}
export default {
state,
getters,
actions,
mutations
}
Here is the middleware function:
import store from '../store';
export default (to, from, next) => {
if (isAuthenticated()) {
if (!hasPermissionsNeeded(to)) {
next('admin/permission-denied');
} else {
next();
}
next();
} else {
next('/admin/session/login');
}
};
function isAuthenticated() {
if (localStorage.getItem("userInfo") != null && localStorage.getItem("userInfo").length > 0) {
return true;
} else {
localStorage.removeItem("userInfo");
return false;
}
};
function hasPermissionsNeeded(to) {
var permissions = store.getters.getPermissions;
if(permissions.includes(to.meta.permissions) || to.meta.permissions == '*') {
return true;
} else {
return false;
}
};
Here is the router logic:
path: "/admin/country",
component: () => import("./views/admin/country/country"),
beforeEnter: authenticate,
meta : {
permissions: 'browse country'
}
I can't see where you're dispatching the userPermission action to load the permissions, but I assume you're only dispatching it somewhere that only gets called after the middleware has run. So it looks like the permissions might not have been loaded by the time you're running the middleware. You might want to dispatch the permission in the middleware, wait for it to finish and only then check the permissions. For example:
export default (to, from, next) => {
store.dispatch('userPermission').then(() => {
if (isAuthenticated()) {
...
})
I'm having an issue where the store data "menus" is not updated after i do a login.
Appearantly.. the object "loggedInUser" is not sat before i call "getMenus".. I'm not sure what i'm doing wrong here...
PS! When debugging in chrome, i notice that loggedInUser is "null" when entering the api call (see api.js codesnippet).
Login.vue (method) :
methods: {
doLogin() {
this.errorMessage = '';
this.loading = true;
let userCredentials = {
'username': this.loginEmail,
'password': this.loginPassword
};
this.$store.dispatch('tryLogin', {
'login': this.loginEmail,
'password': this.loginPassword
}).then((response) => {
this.$store.dispatch('getMenus')
.then((response) => {
this.$router.push('/')
});
});
}
},
Menus.vue (same as /)
computed: {
menus() {
return this.$store.getters.menus
}
},
created() {
this.$store.dispatch('getMenus')
},
methods: {
viewMenu: function(item) {
console.log("=> View Menu : " + item.Name)
this.$router.push('/viewmenu/' + item.Id)
}
}
}
store.js (getMenus action AND tryLogin)
actions: {
getMenus({ commit, getters }) {
api.getMenus(getters.loggedInUser)
.then(menus => {
commit('UPDATE_MENUS', menus);
});
},
tryLogin({ commit }, credentials) {
api.tryLogin(credentials)
.then(loggedInUser => {
commit('LOGGED_IN_USER', loggedInUser);
});
},
api.js (getMenus function)
getMenus(loggedInUser) {
var hostname = 'http://myurl'
var config = {
headers: {
'Content-Type': 'application/json'
}
}
var endpointUrl = hostname + '/api/Menu/GetMenus';
if (loggedInUser != null){
endpointUrl = hostname + '/api/Menu/GetMenusForSubCompany/' + loggedInUser.encryptedsubcompanyid;
}
return axios.get(endpointUrl, config)
.then(response => response.data);
},
From your store.js snippet, it seems you forget to return the promise.
I wonder how to disable a route in VueRouter conditionally, so that it can't be accessed anymore!
I tried to redirect with this.$router.replace('/') but the URL did show the route that I wanted to skip.
Any thoughts?
EDIT:
this is my VUEX-Store: Have a look at router.replace('/')
const store = new Vuex.Store({
state: {
users: [ ],
friendships: [ ],
userID: null
},
mutations: {
signUp(state, payload) {
auth.createUserWithEmailAndPassword(payload.email, payload.password).then((user) => {
if (user !== null) {
state.userID = user.uid
router.replace('/')
}
else {
state.userID = null
}
})
},
signIn(state, payload) {
auth.signInWithEmailAndPassword(payload.email, payload.password).then((user) => {
if (user !== null) {
state.userID = user.uid
router.replace('/')
}
else {
state.userID = null
}
})
},
signOut(state) {
auth.signOut()
state.userID = null
router.replace('/signin')
},
authenticate(state) {
auth.onAuthStateChanged((user) => {
if (user !== null) {
state.userID = user.uid
router.replace('/')
}
else {
state.userID = null
}
})
}
},
actions: {
signUp({ commit }) {
commit('signUp')
},
signIn({ commit }) {
commit('signIn')
},
signOut({ commit }) {
commit('signOut')
},
authenticate({ commit }) {
commit('authenticate')
},
redirect({ commit }) {
commit('redirect')
}
}
})
and here is my component:
<template>
<div id="you">
<h1>you</h1>
<p>You are on your secret page!</p>
<p>{{ $store.state.userID }}</p>
</div>
</template>
<script>
export default {
name: 'you',
beforeCreate() {
if (this.$store.state.userID === null) {
this.$router.replace('/signin')
}
}
}
</script>
You can add a meta feild to that route you want to conditionally disable it like this:
export const routes = [
{path: '/', component: foo},
{path: '/bar', component: bar, meta:{conditionalRoute:true}}
];
And use router.beforeEach in your main.js :
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.conditionalRoute)) {
// this route requires condition to be accessed
// if not, redirect to home page.
if (!checkCondition) {
//check codition is false
next({ path: '/'})
} else {
//check codition is true
next()
}
} else {
next() // make sure to always call next()!
}
})
Or else use beforeRouteEnter() navigation guard locally on that route's component
beforeRouteEnter(to, from, next){
next(vm => {
// access to component instance via `vm`
if(checkCondition){
next();
}else{
next('/');
}
})
}
In your signin component
beforeRouteEnter(to, from, next){
next(vm => {
// access to component instance via `vm`
if(vm.$store.state.userUID !== null){
next('/');
}else{
next();
}
})
}
In your route, you can use navigation guard to check if the route matches the route you want to disable and then return instead of executing next()
router.beforeEach(to, from, next) {
if (to.path === "yourRoute") {
return;
}
}
I have used this link as a reference to make a request before entering a route:
https://router.vuejs.org/en/advanced/data-fetching.html
import Vue from 'vue'
import VueResource from 'vue-resource'
Vue.use(VueResource)
function getCities () {
return Vue.http({
method: 'GET',
url: process.env.base_url + 'cities'
})
}
export default {
data () {
return {
cities: []
}
},
beforeRouteEnter (to, from, next) {
getCities((err, cities) => {
if (err) {
next(false)
} else {
next(vm => {
vm.cities = cities.data
})
}
})
},
watch: {
$route () {
this.cities = []
getCities((err, cities) => {
if (err) {
this.error = err.toString()
} else {
this.cities = cities.data
}
})
}
}
However it doesn't seem to be working for me. I have tested this code and the request is successfully being made. However the result is not being returned. Currently, the request itself is being returned from the function, but I cannot show it in the beforeRouteEnter callback where it supposedly should assign it to vm.cities neither in the watch $route section.
Any help/opinion is appreciated.
The Vue.http method returns a promise, so the code should read:
beforeRouteEnter (to, from, next) {
getCities().then(response => {
next(vm => vm.cities = response.body)
}
}