Используя Angular2, как перенаправить на предыдущий URL-адрес до переадресации входа

Используя Angular2, чтобы создать одностраничное приложение, я перехватываю неавторизованный доступ пользователей к непубличным маршрутам в пользовательском RouterOutlet и перенаправляя их на вид входа. После успешного входа в систему я хочу перенаправить пользователя в свое первоначально запрошенное представление, а не по умолчанию.

Я заметил, что Router имеет функцию renavigate(), которая переместится на последний успешный маршрут, но последний успешный маршрут был /auth/login, а не запрошенный первоначально URL.

В принципе: как я могу получить доступ или определить ранее запрошенный URL?

Я действительно не хочу прибегать к передаче параметров строки запроса, если только мне это не нужно. В идеале было бы неплохо иметь доступ к коллекции history как часть компонента Router, аналогично backbone.history!

Ответ 1

  • Используйте Auth Guard (реализует CanActivate), чтобы предотвратить использование пользователей, не прошедших проверку подлинности. См. официальную документацию с примерами и этот блог.
  • Используйте RouterStateSnapshot в защитнике auth для захвата запрошенного URL.

    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) 
    {
        // keep the attempted URL for redirecting
        this._loginService.redirectUrl = state.url;
    }
    
  • Перенаправить на этот URL-адрес на успешную аутентификацию с помощью Router (например, в login.component.ts). Например. this._router.navigateByUrl(redirectUrl);

P.S. Предложения @MichaelOryl и @Vitali будут работать, но мой способ более согласован с окончательной версией Angular2.

Ответ 2

Вы можете найти то, что вам нужно в docs для класса Location. Функция back() может сделать это для вас.

Другим подходом было бы подписаться на события popstate в Location. MDN имеет документы, говорящие о значениях, которые вы могли бы ожидать получить.

class MyCLass {
  constructor(private location: Location) {
    location.subscribe((val) => {
        // do something with the state that passed in
    })
  }
}

В противном случае вам может понадобиться служба, которая отслеживает изменения в маршрутизаторе, чтобы вы могли получить к ним доступ.

class MyTrackingService {
  constructor(private router: Router) {
    router.subscribe((val) => {
        // store the routes here so that you can peel them off as needed?
    })
  }
}

В этом случае я обращаюсь к объекту Router и подписываюсь на любые изменения, чтобы отслеживать их.

Ответ 3

Это сработало для меня. Внесите его в свой основной конструктор компонента приложения, зарегистрировав его в методе начальной загрузки. Первым val при загрузке страницы должен быть исходный URL. Я отказываюсь от подписки сразу после того, чтобы быть эффективным, так как я не (возможно, еще) хочу слушать последующие события маршрутизатора в этой службе. Внесите сервис в другие места, где требуется исходный url.

import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { Subscription } from 'rxjs/Subscription';

@Injectable()
export class UrlTrackingService {

  public originalUrl: string;

  constructor(
    private router: Router
  ) {
    let subscription: Subscription = this.router.events.subscribe((val) => {
      this.originalUrl = val.url;
      subscription.unsubscribe();
    });
  }

}

Ответ 4

Обновленный пример Использование Angular 2.2.1

Auth Guard, который передает исходный URL-адрес компоненту входа:

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

@Injectable()
export class AuthGuard implements CanActivate {

    constructor(private router: Router) { }

    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
        if (localStorage.getItem('currentUser')) {
            // logged in so return true
            return true;
        }

        // not logged in so redirect to login page with the return url
        this.router.navigate(['/login', { returnUrl: state.url }]);
        return false;
    }
}

import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';

import { AlertService, AuthenticationService } from '../_services/index';

@Component({
    moduleId: module.id,
    templateUrl: 'login.component.html'
})

Входной компонент, перенаправляющий предыдущий/оригинальный URL-адрес после входа в систему:

export class LoginComponent implements OnInit {
    model: any = {};
    loading = false;
    returnUrl: string;

    constructor(
        private route: ActivatedRoute,
        private router: Router,
        private authenticationService: AuthenticationService,
        private alertService: AlertService) { }

    ngOnInit() {
        // reset login status
        this.authenticationService.logout();

        // get return url from route parameters or default to '/'
        this.returnUrl = this.route.snapshot.params['returnUrl'] || '/';
    }

    login() {
        this.loading = true;
        this.authenticationService.login(this.model.username, this.model.password)
            .subscribe(
                data => {
                    // login successful so redirect to return url
                    this.router.navigate([this.returnUrl]);
                },
                error => {
                    // login failed so display error
                    this.alertService.error(error);
                    this.loading = false;
                });
    }
}

Для получения дополнительной информации и рабочей демонстрации вы можете проверить этот пост