Запретить маршрутизацию в Angular, когда пользователь вручную меняет URL на вкладке браузера

Я застрял в проблеме, которая возникает, когда пользователь вручную меняет маршрут на вкладке браузера и нажимает ввод. Это заставляет мой ui-router/angular2-router перейти в состояние, введенное пользователем. Я хочу предотвратить это и разрешить маршрутизацию только через поток, который я реализовал нажатием кнопки на моем веб-сайте.

4 ответа

Решение

Свой 2018 год! Angular 5 здесь, и поэтому решение этой проблемы. BAMM его интерфейс CanActivate, который класс может реализовать, чтобы быть защитником, решающим, можно ли активировать маршрут.

Мы можем добавить эту функцию и запретить доступ к некоторым из наших маршрутов на основе определенных нами условий. Сервис, например, AuthGuard, который реализует интерфейс CanActivate и определяет метод canActivate, может быть добавлен в конфигурацию маршрута.

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);
  }
}

Если у нас есть маршрут, доступ к которому мы хотим защитить от каких-либо условий, мы добавляем защиту следующим образом:

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 }
];

Здесь маршрут heroes и все его дети имеют слой охраны над ним. Следовательно, на основе логического значения, возвращаемого службой AuthGuard, пользователю будет разрешен или запрещен доступ к этому маршруту.

Вы можете импортировать роутер в конструктор гвардии. Этот экземпляр маршрутизатора будет иметь текущий URL. ActivatedRouteSnapshot и RouterStateSnapshot в canActivate будут содержать URL-адрес, к которому пользователь пытается получить доступ.

Приведенный ниже пример запрещает пользователям прямой доступ к маршруту с внешней страницы.

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;
  }
}

Добавьте эту защиту в ваш модуль маршрутизации

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

Кажется, это старая проблема, но я тоже застревал здесь, пока не получил что-то, работающее для моего приложения.

Что вы можете сделать, чтобы воспрепятствовать прямому манипулированию URL-адресом браузера:

1) Имейте статическое логическое поле в вашем приложении, экспортированное повсюду. Допустим, это Helper.isNextStep (сохраните файл как helper.ts).

export class Helper {
static isNextStep: boolean; }

2) Установите для этого статического поля значение false при просмотре страницы (это легко сделать в конструкторе app.component.ts) как:

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

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

    Helper.isNextStep = false;

    })
 }}

3) Настройте защиту canActivate, например:

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) Сделайте так, чтобы эта защита canActivate была предоставлена ​​в app.module.ts

providers: [ AuthGuard ]

и app.route.ts:

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

После всего этого... вам просто нужно установить Helper.isNextStep равным true везде, где вы будете использовать навигацию в своем приложении. (Например, нажатие кнопки, вызывающее функцию, поэтому перед навигацией просто установите для статического поля значение true)

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

Когда следующая страница загружается, она автоматически возвращается к false, не позволяя URL-адресу измениться.

Напишите этот код в app.js.

.run(['$rootScope', '$state', '$stateParams','LoginStatusService',function($rootScope, $state, $stateParams,LoginStatusService) {
    $rootScope.$state = $state;
    $rootScope.$stateParams = $stateParams;

    $rootScope.$on('$stateChangeSuccess', function(event, toState) {
        //Write Routes login here
        if(LoginStatusService.getUserStatus()===false){
           $state.go('core.login');

        } 
   });
}])

$stateChangeStart Событие - подходящее место, чтобы справиться с этим. Это событие будет срабатывать при попытке перейти к URL, В этот момент вы можете проверить, аутентифицирован ли пользователь, и, если нет, вернуть его обратно для входа в систему.

Вы бы подключили событие так:

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

Надеюсь, поможет.

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;
        }
    }
Другие вопросы по тегам