Запретить маршрутизацию в 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;
}
}