I'm trying to use 'router.beforeEach' for checking token.
chrome can enter in beforeEach, but safari couldn't.
is there anything I have to know before use 'beforeEach' in safari?
I'm so confused and this problem makes me crazy.
here is code. there are meta : {authRequired: true} every components except login component.
router.beforeEach(function (to, from, next) {
console.log("I'm in!!!")
let token = VueCookies.get('jwtToken');
let isAuthenticated = token !== null;
if (to.matched.some(function(routerInfo) {
return routerInfo.meta.authRequired;
})) {
if(!isAuthenticated) {
if(to.name != 'login') {
next({name: 'login'});
}
}else {
next();
}
}else {
next();
}
})
Google Chorme
Safari so---------clean....
can I use beforeEach in safari?
Related
This works for me if the user isn't logged in, however the else if wont work at all even though the route path is "/login" and main.authState is true. How do I set this up properly?
router.beforeEach((to, from, next) => {
const main = useAuthStore(router.pinia);
if (to.matched.some((record) => record.meta.authRequired)) {
if (!main.authState) {
return next("/login");
}
} else if(to.matched.some((record) => !record.meta.authRequired)) {
if (to.path == "/login" && main.authState == true) {
alert(to.path) //"/login"
alert(typeof(main.authState)) //"boolean"
return next();
}
}
next();
});
async signOut() {
await auth.logout();
await localStorage.removeItem("authenticated");
await router.replace({ name: "Login" });
},
If auth is not required for some route, you should not check for authState.
If I didn't understand correctly, explain.
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.authRequired)) {
const { authState } = useAuthStore(router.pinia);
// Ensure what authState is true to proceed to next() route
authState
? next()
: next('/login');
} else {
next();
}
});
You could use a URL query param to store the redirect target, which you then access from your Login.vue component, and can set a default value to redirect to when the user accesses the /login route as an authenticated user without a predefined redirect.
router.beforeResolve(async (to, from, next) => {
if (to.matched.some((record) => record.meta.authRequired)) {
const lastMathcedRoute = to.matched[to.matched.length - 1].path || "/";
// "/" is just a fallback route
const main = useAuthStore(router.pinia);
const isAuthenticated = main.authState;
if (!isAuthenticated ) {
next({ path: "/login", query: { redirect: lastMathcedRoute } });
} else {
next();
}
} else {
next();
}
});
And then in your Login component, you just access the redirect query param if user is already authenticated or when his auth state changes. Basically you need to somehow be notified, or watch the auth state and redirect the user accordingly. So you need authState to be a ref or reactive object that you can watch.
// Login.vue
import { useRouter } from "vue-router";
setup() {
const router = useRouter();
const { authState } = useAuthStore(router.pinia);
watch(authState, () => {
if (authState) {
const redirectLocation = route.query?.redirect?.toString() || '/pannel';
// here '/panel' is the default redirect
return router.push(redirectLocation);
}
}, { immediate: true } )
}
PRO Tip: notice { immediate: true }, this makes it so that the watch immediately fires with the initial value of the authState, instead of firing just when it changes. This is helpful in the case that the authState is already true and it does not change.
You can use other mechanisms instead of a watcher, but in principle the solution is the same.
I added this code in my router:
Router.beforeEach((to, from, next) => {
// redirect to login page if not logged in and trying to access a restricted page
const publicPages = ['/login']
const authRequired = !publicPages.includes(to.path)
const user = <Utilisateur>JSON.parse(<string>localStorage.getItem('user'))
// console.log('user', user, authRequired, to, from, next)
if (authRequired && !user && to.path !== '/connexion') {
// console.log('redirect')
next({ name: 'connexion', query: { from: to.fullPath } })
}
next()
})
This warning message is displayed when the redirection is triggered, do you know how I can solve this problem?
|Vue Router warn]: The "next" callback was called more than once in one navigation guard when going from "/" to "/". It should be called exactly one time in each navigation guard. This will fail in production.
You should add else block that runs next():
Router.beforeEach((to, from, next) => {
// redirect to login page if not logged in and trying to access a restricted page
const publicPages = ['/login']
const authRequired = !publicPages.includes(to.path)
const user = <Utilisateur>JSON.parse(<string>localStorage.getItem('user'))
// console.log('user', user, authRequired, to, from, next)
if (authRequired && !user && to.path !== '/connexion') {
// console.log('redirect')
next({ name: 'connexion', query: { from: to.fullPath } })
} else{
next()
}
})
for more details please check this
I am scratching my head trying to figure out the logic in my vue router so so Vue will remember an entry URL, redirect to "/Login" if not authenticated, then redirect to the entry URL after login.
I think I've just been staring at this too long and could use some fresh eyes. Thoughts on where I've gone astray here?
...
let entryUrl = null;
router.beforeEach((to, from, next) => {
let locStorage = JSON.parse(localStorage.getItem("userData"));
let stateStore = state.getters.getUserData;
let userData = locStorage || stateStore;
let isAuthenticated = userData.token !== "" && userData.token !== undefined;
let url;
if (to.matched.some((record) => record.meta.requiresAuth)) {
if (!isAuthenticated) {
if (to.fullPath !== "/login" && to.fullPath !== "/") {
entryUrl = to.fullPath;
console.log("setting", entryUrl);
}
next({ name: "Login" });
} else {
console.log("entry", entryUrl);
url = entryUrl || "/";
entryUrl = null;
console.log("url", url);
next();
}
} else {
next();
}
});
You could use a vuex store for that. In the store you could save the url before the redirect to the /login and after the login you could check if there is an url saved and redirect to that.
You only have to make sure that you pass in the store instance into your logic which creates the router-handler.
I do't know what is happening here. I made simple app with 2 screens, on login success i want to change screen on HomePage. I am using redux, redux-saga and axios with react-native
My submit function on login screen is:
async submit() {
if(this.state.email.length == 0 || this.state.password.length == 0) {
alert("Filed is required")
} else {
if(typeof this.state.email !== 'undefined') {
if(!this.state.email.match(/[^#]+#[^.]+\..+/)) {
alert("E-mail format wrong!")
} else {
console.log('ok auth');
let user = {
email: this.state.email,
password: this.state.password
}
this.props.login(user)
}
}
}
}
Login saga write token in AsyncStorage, on login success and it works fine
export function* loginUser(action) {
const response = yield call(login_api, action.payload)
if(!response || !response.data) {
console.log('wrong login 1: ', response);
//status 422 Unprocessable Entity
return yield put(login_failure('Internal server error for login user'))
}
if(response.status === 200) {
deviceStorage.saveItem('token', response.data.token)
return yield put(login_success(response.data, response.data.token))
} else {
console.log('wrong login 2');
return yield put(login_failure('Error for login user'))
}
}
On login success, reducer returns token i Login.js and then I want to redirect in HomePage. I want to logout user every time when he comes on login page, because I use componentDidMount()
async componentDidMount() {
await deviceStorage.deleteToken('token')
}
componentWillReceiveProps(nextProps) {
console.log('enxtProps: ', nextProps.token.length);
if(nextProps.token.length > 0) {
//TOKEN EXISTS!!! length = 365
this.props.navigation.navigate('HomePage')
} else {
console.log('Error login');
}
this.setState({
token: nextProps.token
})
}
this.props.navigation.navigate('HomePage') in componentWillReceiveProps doesn't redirect on HomePage.
Can someone tell me why?
I have a couple of suggestions for your code.
In Login-Saga wait until token saved
deviceStorage.saveItem('token', response.data.token)
change to
yield deviceStorage.saveItem('token', response.data.token)
Don't use componentWillReceiveProps. It is marked as unsafe in react & remove after version 17. Use componentDidUpdate as below.
componentDidUpdate(prevProps) {
// Typical usage (don't forget to compare props)
if (this.props.token !== prevProps.token && this.props.token.length > 0) {
this.props.navigation.navigate('HomePage')
} else {
console.log('Error login');
}
}
I have router which work with errors and can't understand how to fix it.
This global router which should check jwt token expiration and handle routing. Everything worked fine before adding some functionality like isActivated account. So now I need to check if User has token and if User account is activated.
1) If user has token it should make next() otherwise next("/login") (redirect)
2) If user has token but his account is not activated yet (first time login), it should redirect on Setup page next("/setup") until he submits some information.
So this is my guard
router.beforeEach((to, from, next) => {
const token = localStorage.getItem("token");
const tokenExp = parseInt(localStorage.getItem("tokenExp"))
const isActivated = localStorage.getItem("isActivated")
const now = new Date().getTime() + 129600000
const requiresAuth = to.matched.some(record => record.meta.requiresAuth);
console.log("first")
if (requiresAuth && !token) {
next('/login');
} else if (requiresAuth && token) {
if (now > tokenExp) {
axios.post("/user/t/r", token)
.then(e => {
const token = e.headers['authorization'].replace("Bearer ", "");
localStorage.setItem("token", token);
localStorage.setItem("tokenExp", (new Date().getTime() + 172800000).toString())
if (isActivated === 'true') {
next()
} else {
next("/setup")
}
})
.catch(e => {
localStorage.removeItem("token")
localStorage.removeItem("tokenExp")
localStorage.removeItem("fullName")
localStorage.removeItem("role")
next('/login')
})
} else {
console.log("second")
if (isActivated === 'true') {
console.log("third")
next();
} else {
console.log("fourth")
next("/setup")
}
}
} else {
next();
}
})
And this is my console.log with error when I login:
You are infinitely redirecting to /setup, You code on first run hits "fourth" then sends the user to /setup where that before call is run again and your infinite loop starts.
You need to stop calling next('/setup') or next('/login') if the user is already on that page.
You need to make use of router.currentRoute in order to check you are not going to redirect to page they are already on.
https://router.vuejs.org/api/#router-currentroute