I am learning Vue JS and so far so good. I have an API which I am using for my backend and on successful login, it is giving me access and a refresh token. In Vue, I am checking localStorage for the token and if null I need to redirect to the login page. If present I need to make an API call to check if valid and redirect to log in or the intended route depending on the response. So far the code below is what I have managed to put up but is saying Detected an infinite redirection in a navigation guard when going from "/" to "/". Aborting to avoid a Stack Overflow. This will break in production if not fixed
Here is may code
router.beforeEach((to, from, next ) =>{
console.log(to.meta)
let tokens = JSON.parse(localStorage.getItem('chikolo_tokens'))
if (tokens!== null && to.meta.requiresAuth) {
next()
}
else{
next({ name: 'login' })
}
})
Routes
{
path: '/',
name: 'login',
component: Login,
meta: { requiresAuth: false },
},
{
path: '/admin/home/',
name: 'home',
component: AdminHome,
meta: { requiresAuth: true },
},
{
path: '/admin/users/',
name: 'adminUsers',
component: Users,
meta: { requiresAuth: true },
},
How do I navigate to the login page if tokens is null?
tokens!== null && to.meta.requiresAuth is always false for / route.
A redirect should happen only for routes that require auth:
if (to.meta.requiresAuth && !tokens) {
next({ name: 'login' })
} else{
next()
}
Kindly try this
const routes = [
/** admin*/
{
path: '/admin/home',
name:'adminHome',
component: homeAdminIndex,
meta:{
requiresAuth :true
}
},
/** pages*/
{
path: '/',
name:'Home',
component: homePageIndex,
meta:{
requiresAuth :false
}
},
router.beforeEach((to,from) =>{
if (to.meta.requiresAuth && !localStorage.getItem('token')){
return { name: 'Login'}
}
if (to.meta.requiresAuth == false && localStorage.getItem('token')){
return { name: 'adminHome'}
}
})
Related
I have a standard set of Routes:
export const ROUTES: Routes = [
{
path: '', redirectTo: 'home'
},
{
path: 'notentitled', component: 'NotEntitledComponent'
},
{
path: 'welcome', component: 'WelcomeComponent', canActivate: [RoutingService]
},
{
path: 'active', component: 'ActiveComponent', canActivate: [RoutingService]
},
{
path: 'table', component: 'TableComponent', canActivate: [RoutingService]
},
{
path: '**', component : NotFoundComponent
}
];
The canActivate method pulls in the users entitlement credentials and checks the target route ie 'active' against their entitlement ie:
public canActivate(route: ActivateRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
let target = state.url;
return entitlementService.getUserInfo()
.pipe(
map(data => {
let canSeePage = data?.entitlements?['target'];
return canSeePage;
}),
catchError((error: any) => {
route.navigate(['notentitled']);
return of(false);
});
}
I want to add some logic to cater to a scenario. If in the entitlement check ie:
let canSeePage = data?.entitlements?['target'];
false; before returning false; check if user can see any other page and redirect there.
Example, user requests 'active' route, however, this fails:
let canSeePage = data?.entitlements?['target']; // ie data.entitlements.active: false
However, data.entitlements.table is true, so redirect to 'table'
i have two routes :-
1- http://localhost:4200/members/10 ===> this for member's page
2- http://localhost:4200/members/10?tab=3 ===> this for chat page
I want to make chat as a paid service so I create component I called it charge with this route ==> http://localhost:4200/charge so if any member like to go to chat route he will be redirected to charge page as I create code in ngOnInit method in chat component like that
if(!this.authService.paid)
{this.router.navigate(['charge']);}
When I go chat it redirects me to charge page and that's cool , the problem is that when I go member'page it redirects me to charge page and that's not cool at all, so please help me what can i do to solve this problem, thanks in advance
and this is my routes
export const appRoutes: Routes = [
{ path: '', component: HomeComponent },
{
path: '',
runGuardsAndResolvers: 'always'
, canActivate: [AuthGuard],
children: [
{
path: 'members', component: MemberListComponent, resolve: {
users: MemberListResolver
}
},
{
path: 'member/edit', component: MemberEditComponent, resolve: {
user: MemberEditResolver
}, canDeactivate: [PreventUnsavedChangesGuard]
},
{
path: 'members/:id', component: MemberDetailComponent, resolve: {
user: MemberDetailResolver
}
},
{
path: 'lists', component: ListsComponent, resolve: {
users: ListResolver
}
},
{ path: 'messages', component: MessagesComponent, resolve: { messages: MessageResolver }, canActivate: [MessagesGuard] },
{ path: 'charge', component: PaymentComponent }
]
},
{ path: '**', redirectTo: '', pathMatch: 'full' }
];
It looks like you use the same ngOnInit implementation for both pages '/member' and '/chat'. And if this !this.authService.payed returns true, you will always be redirected to '/charge' page.
But to have a better understanding, please provide your routing configuration.
Edit:
Thank you for adding your routes.
{
path: 'members/:id', component: MemberDetailComponent, resolve: {
user: MemberDetailResolver
}
}
It seems like you check for !this.authService.payed in MemberDetailComponent#ngOnInit, but you probably do not check your queryParam ?tab=3.
To fix this issue quickly you can modify your if-condition:
if(!this.authService.payed && this.route.snapshot.queryParams['tab'] === 3)
where this.route has to be injected via constructor parameter
constructor(private route: ActivatedRoute)
But
I think the best solution for this issue would be to add another child route for chat page and handle authorization with another 'canActivate'.
I am trying to create a SPA which shows dealer in every state of austria. For example if a user visits example.com/vienna it shows every dealer in vienna. But if a users visits example.com/paris, he will still get directed to the dynamic route /paris but of course there will be nothing shown.
So my approach was to check if the state which the user wants to search for is available in the list of state and therefore directing it to the available state or redirect him to a 404 page.
If the state is available it works, but if I'll try to go to a non existing state I am stuck in a loop from next('/404')
export default new Router({
routes: [{
path: '/',
name: 'Home',
component: Home
},{
path: '/:region',
component: RegionQuery,
beforeEnter: (to, from, next) => {
let isRegion = false;
let allRegions = storeConfig.state.states;
let toRegion = to.params.region;
for(var i in allRegions){
if(allRegions[i].route === toRegion){
isRegion = true;
}
}
if (isRegion) {
next();
} else {
next('/404');
}
}
},
{
path: '/404',
name: '404',
component: NotFound
},
{
path: '*',
redirect: '/404'
},
],
})
What am I doing wrong or is there a better approach to my problem?
/404 is matched to /:region
You need to change your path order
export default new Router({
routes: [{
path: '/',
name: 'Home',
component: Home
},
{
path: '/404',
name: '404',
component: NotFound
},{
path: '/:region',
component: RegionQuery,
beforeEnter: (to, from, next) => {
let isRegion = false;
let allRegions = storeConfig.state.states;
let toRegion = to.params.region;
for(var i in allRegions){
if(allRegions[i].route === toRegion){
isRegion = true;
}
}
if (isRegion) {
next();
} else {
next('/404');
}
}
},
{
path: '*',
redirect: '/404'
},
]
nprogress works just fine in every other regard, but on redirect to /login it spins forever. I've attempted the showProgressBar: false to no avail.
If user is logged in they'll be redirected to /dashboard, if they are not they will be redirected to /login.
My code looks like this:
const routes = [
{path: '/', name: 'root', redirect: { name: 'login' }, meta: {showProgressBar: false}},
{path: '/login', component: LoginPage, name: 'login', beforeEnter: loggedIn, meta: {showProgressBar: false}},
{path: '/dashboard', component: DashboardPage, name: 'dashboard', meta: { requiresAuth: true }},
{path: '/editor', component: PhoneEditorPage, name: 'editor', meta: { requiresAuth: true }},
{path: '/usersettings', component: PinPasswordPage, name: 'pinpassword', meta: { requiresAuth: true }},
{path: '/callforwarding', component: CallForwardingPage, name: 'callforwarding', meta: { requiresAuth: true }},
{ name: 'dropdown', path: '/dropdown', component: Dropdown, meta: { requiresAuth: true }}
]
const router = new VueRouter({
linkActiveClass: 'active',
mode: 'hash',
routes
})
function loggedIn (to, from, next) {
const authUser = JSON.parse(window.localStorage.getItem('authUser'))
if (authUser && authUser.auth) {
next({name: 'dashboard'})
} else {
next()
}
}
router.beforeEach((to, from, next) => {
if (to.meta.requiresAuth) {
const authUser = JSON.parse(window.localStorage.getItem('authUser'))
if (authUser && authUser.auth) {
next()
} else {
next({name: 'login'})
this.nprogress.done()
}
}
next()
Thank you for your time.
Isn't simple to answer without see code in action, but, you can try to invert call to this.nprogess.done() and next(...) like this:
router.beforeEach((to, from, next) => {
if (to.meta.requiresAuth) {
const authUser = JSON.parse(window.localStorage.getItem('authUser'))
if (authUser && authUser.auth) {
next()
} else {
this.nprogress.done(); // <- HERE
next({name: 'login'})
}
}
next()
}
since next() call move context to new component, and I'm not sure call to nprogress will be called on the right moment.
I'm fairly new to vue.js and I'm currently trying to setup my different routes. I'm using sub routes, since the "logged in" user will have a different UI than a visitor.
Currently my setup is like this:
routes: [
{
path: '/auth',
name: 'auth',
component: test,
meta: {
auth: false
},
children: [
{
path: 'login',
name: 'login',
component: login
},
{
path: 'signup',
name: 'signup',
component: signup
}
]
},
{
path: '/user',
name: 'user',
component: test,
meta: {
auth: true
},
children: [
{
path: 'profile',
name: 'profile',
component: login
}
]
}
]
While this is working, I'm wondering why child routes don't take over the parents meta properties. Do I need to assign the meta.auth to each sub route? Or is there any way to inherit this?
Essentially in the router.beforeEach, I want to check if the user is authenticated correctly or not. But only on child routes of /user
I'm also coming from an angular background, so I'm used to nesting routes, not sure if this is the best way in Vue.
To answer my own question: https://github.com/vuejs/vue-router/issues/704
I didn't realise this was deprecated in Vue-router 2.0, it is possible to get the matched route and find the meta there.
With vue-router v.3 to match parent's meta (for example: in beforeEach() func. ) You need to use to.matched.some() like this:
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.auth)) {
// ...
next({name:'route-name'})
} else {
next()
}
}
https://router.vuejs.org/guide/advanced/meta.html