Prevent routing in Angular when user manually changes url in browser tab

how to restrict direct url access in angular 2
angular routing
angular routes not working in production
routing angular 8
angular routing children
angular url parameters
angular module routing
angular use hash routing

I am stuck in a issue that happens when user manually changes the route in browser tab and presses enter. This forces my ui-router/angular2-router to navigate to the state entered by user. I want to prevent this and allow routing only through the flow I have implemented by button clicks in my website.

Its 2018! Angular 5 is here and so is the solution to this issue. BAMM its CanActivate Interface that a class can implement to be a guard deciding if a route can be activated.

We can add this functionality and prevent the access to some of our routes based on the conditions we define. A service for eg AuthGuard that implements the CanActivate interface and defines the canActivate method can be added to route configuration.

class Permissions {
  canGoToRoute(user: UserToken, id: string): boolean {
    return true;
  }
}

@Injectable()
class AuthGuard implements CanActivate {
  constructor(private permissions: Permissions, private currentUser: UserToken) {}

  canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<boolean>|Promise<boolean>|boolean {
    return this.permissions.canGoToRoute(this.currentUser, route.params.id);
  }
}

If we have a route that we want to protect access to against some condition, we add the guard as follows:

const appRoutes: Routes = [
  { path: 'crisis-center', component: CrisisListComponent },
  {
    path: 'heroes',
    canActivate: [AuthGuard],
    component: HeroListComponent,
    data: { title: 'Heroes List' }
  },
  { path: '',
    redirectTo: '/heroes',
    pathMatch: 'full'
  },
  { path: '**', component: PageNotFoundComponent }
];

Here the route heroes and all its children have a layer of guard over it. Hence based on the boolean value returned by the AuthGuard service the user will be allowed or denied access to this route.

404 when manually changing URL in browser to defined router , More importantly why is the Angular App giving a 404 Error if a user manually changes the URL in the browser to a valid router route path? I am stuck in a issue that happens when user manually changes the route in browser tab and presses enter. This forces my react router to navigate to the state entered by user. I want to prevent this and allow routing only through the flow I have implemented by button clicks in my website.

You can import router in the constructor of a guard. This router instance will have the current URL. ActivatedRouteSnapshot and RouterStateSnapshot in canActivate will contain the URL that the user is attempting to access.

The below example prevents users from directly accessing a route from an outside page.

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
import { Observable } from 'rxjs/Observable';

@Injectable()
export class DirectAccessGuard implements CanActivate {
  constructor(private router: Router) {}

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
    // If the previous URL was blank, then the user is directly accessing this page
    if (this.router.url === '/') {
      this.router.navigate(['']); // Navigate away to some other page
      return false;
    }
    return true;
  }
}

Add this guard to your routing module

{ path: 'signup/:type/:step', component: SignupComponent, canActivate: [DirectAccessGuard] }

Prevent Routing To Secondary View If Page Refresh In Angular 5.0.0, As I've been digging into the Angular Router, I've made a decision to try and push the "secondary" named-outlet from the UrlTree and redirect the user to the new URL. import { BrowserModule } from "@angular/platform-browser"; Changing The Hash With The Location Service In Angular 4.4.0-RC.0  In most cases, you’ll use the Angular CLI to create projects with routing setup but in this case, we’ll add it manually so we can get a better idea how routing works in Angular. Adding The Routing Module. We need to add AppRoutingModule which will contain our application routes and a router outlet where Angular will insert the currently matched component depending on the browser current URL. We’ll see: How to create an Angular Module for routing and import it; How to add routes to

Seems to be an old issue but i was also stuck here until i got just a thing working for my application.

What you can do to discourage direct browser url manipulation is :

1) Have a static boolean field in your application exported throughout. Let's say it's Helper.isNextStep (save the file as helper.ts).

export class Helper {
static isNextStep: boolean; }

2) Set this static field to false on a page view (easily done in app.component.ts constructor) as :

  import {Helper} from '../path/to/helper.ts' 

  export class AppComponent {
  constructor() {
  location.onPopState(() => {

    Helper.isNextStep = false;

    })
 }}

3) Have the canActivate gaurd set up like :

import { Helper } from '../path/to/helper.ts'
import { CanActivate } from '@angular/router/router';
import { Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
@Injectable()
export class AuthGuard implements CanActivate {
constructor(public zone: NgZone, public router: Router) {

}
canActivate(): boolean {
if (!Helper.isNextStep) {
  this.zone.run(() => {
    this.router.navigate(['']) //you can redirect user to any page here ( Optional )
  })
  return false;  //block navigation
}
else {
  return Helper.isNextStep || true;  // allow navigation
}
}

4) Have this canActivate gaurd provided in app.module.ts

providers: [ AuthGaurd ]

and app.route.ts :

  {
path: 'step2',
component: ProductOverviewComponent,
canActivate: [AuthGuard]
},

After all this... you simply need to set the Helper.isNextStep equal to true wherever you will use navigation in your app. (For example a button click that calls a function, so before navigating simply set the static field to true )

someButtonClickFunction() {
    Helper.isNextStep = true;
    this.zone.run(() => {
        this.router.navigate(['/step1']);
    });
}

When the next page is loaded it will automatically be set back to false, not allowing url to change.

Angular Router: An Introduction to Component Routing, Jurgen teaches Angular routing from scratch, showing how to update an Angular app a user clicks a link in the browser, causing the URL to change create a new file src/todos.resolver.ts manually and add the following code: If you open up the network tab of your developer tools, you'll see that the  Both solution work but when changing the URL manually in the browser URL bar, router triggers two navigation events: Expected behavior. Router should trigger only one navigation event, as it does when navigating programmatically (meaning not changing manually the URL). Minimal reproduction of the problem with instructions. Demo with component redirection

The $stateChangeStart event is the proper place to handle this. This event will fire when you try to navigate to a URL. At that point you can check if the user is authenticated, and if not, bounce them back to login.

You would hook up the event like this :

angular
  .module('myApp')
  .run(function ($rootScope, $state, authFactory) {
    $rootScope.$on('$stateChangeStart', function () {
      //if user is not logged in
      if(!authFactory.isAuthed()){ 
        $state.go('login')
      }
    })
  });

Hope it helps.

Angular Router: Using Route Guards ← Alligator.io, Learn how to use routing guards in Angular to control accessing or leaving a user from accidentally leaving a component with unsaved changes. doesn't prevent the user from closing the browser tab or navigating to a  brookhutchinson changed the title 404 when changing URL to defined router route 404 when manually changing URL in browser to defined router route Feb 28, 2017

canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
        if (this.auth.fnGetToken()) { //check token
            const role = this.auth.fnGetLoginUser(); //get login user data
            if (role.selRole !== 'admin' && (state.url === '/users' || state.url === '/users/')) {
                this.router.navigate(['contacts']);
                return false;
            } else {
                return true;
            }
        } else {
            this.router.navigate(['Login']);
            return false;
        }
    }

Routing & Navigation - ts - GUIDE, When the browser's URL changes, that router looks for a corresponding Route from which it It has RouterLink s that users can click to navigate via the router. Return that promise to prevent the route from loading until the data is fetched. If my understanding of reloadOnSearch is correct, it only changes behaviour when the query string or hash change, not the URL path, which is what was required here. This comment has been minimized. Sign in to view

Router, Determines when the router updates the browser URL. By default ( "deferred" ), updates the browser URL after navigation has finished. Set to 'eager' to update  I have looked into the router hooks CanActivate and CanDeactivate and implemented them but CanDeactivate does not fire at all when using direct browser navigation. I can use CanActivate to prevent the url but only after the app reboots, which takes time and undesired changes in the browser window.

Router Guards • Angular, With Router Guards we can prevent users from accessing areas that they're not allowed to We might ask the user if it's OK to discard pending changes rather than save them. Angular will keep the user waiting until the guard returns true or false . console.log(route.params); console.log(state.url); return component. In early Angular versions, there was no option to tell the router to emit events on same route refresh. Angular 5.1 introduced the onSameUrlNavigation property on the routers ExtraOptions.

Using the Angular Router to navigate to external links, Navigating to an external url from an Angular application is have a guard that notifies the user of any unsaved changes and can stop the  Add the following code to webpack.config.js to prevent 404 errors when the browser is refreshed. It tells the webpack dev server to always serve /index.html regardless of the URL path so Angular can initialise and handle routing instead of trying to handle it on the server. devServer: { historyApiFallback: true }

Comments
  • not possible without using some dirty way.
  • please suggest if any.
  • It is quite possible, please go trhough this link github.com/angular-ui/ui-router/wiki.. All you need to listen $stateChnageStart event which angular fire whenever there is a change in navigation and write some logic to stop from navigating.
  • @immirza no, it is not possible because you can simply come to a webpage without being inside of angular yet.
  • It is very much possible, as i said you need to right logic right after listening the event. If something wrong, keep user on same url else navigate to new url. i believe i have done it.
  • How do you detect the navigation is triggered by url changes manually or internal router navigate method?
  • @SamratSaha you can check the userToken/Permisiions. If its available, then routing must be internal, else the same must be by entering route in url directly.
  • i am getting a deadlock situation here
  • For the implementation I am doing I made a smalls changes to your proposal that avoided some problems with the onPopState. I declared the variable isNextStep in helper.ts as false: static isNextStep: boolean = false; and instead of calling location.onPopState (() => {...}); in the constructor directly I did the Helper.isNextStep = false; Which is working very well and now I have full control of the application because I can configure each of the pages to work or not with the guard.
  • @Alejandro Glad that this could help ! Thanks for adding this for the readers.
  • Thanks for your solution but the thing is the user is authenticated, I just want to prevent him from accessing the states by manually changing the url. This way he may reach a state that should have got data from previous screen in sequence but because of abrupt routing it will be empty.
  • Please provide some context in your answer so the OP knows how your solution solves his/her problem
  • It is not a valid solution to the question asked.