Аутентификация Angular 2 с дочерними маршрутами

У меня есть приложение angular 2, в котором мне нужно пройти аутентификацию на каждой странице. Поэтому я реализовал собственный RouterOutlet, чтобы подтвердить, что я вхожу в систему при каждом изменении страницы.

@Directive({
   selector: 'auth-outlet'
})
export class AuthOutlet extends RouterOutlet {
   publicRoutes: any;
   private parentRouter: Router;
   private authService: AuthService;
   constructor(_elementRef: ElementRef, 
               _loader: DynamicComponentLoader, 
               _parentRouter: Router,
               @Attribute('name') nameAttr: string, 
               _authService: AuthService) {

      super(_elementRef, _loader, _parentRouter, nameAttr);
      this.parentRouter = _parentRouter;
      this.authService = _authService;
      this.publicRoutes = {
          'Login': true
      };
  }

  activate(oldInstruction: ComponentInstruction) {
      var url = this.parentRouter.lastNavigationAttempt;
      console.log('attemping to nav');
      if (!this.publicRoutes[url] && !this.authService.loggedIn){
          var newInstruction = new ComponentInstruction('Login', [], new RouteData(), Login, false, 1);
          return super.activate(newInstruction);
      } else {
          return super.activate(oldInstruction);
      }
   }
}

Вот рабочий код: http://plnkr.co/edit/YnQv7Mh9Lxc0l0dgAo7B?p=preview

Есть ли лучший способ перехватить изменения маршрута и перенаправить для входа в систему, когда пользователь не аутентифицирован?


person Karl L    schedule 12.02.2016    source источник
comment
Превосходно!! Что еще нужно!!   -  person micronyks    schedule 13.02.2016
comment
Ну, во-первых, вы не должны создавать новую ComponentInstruction. Так что с этим уже есть проблемы. Кроме того, у него есть проблемы, если вы находитесь на дочернем маршруте, который не знает о маршруте входа. (Я работал над этим вопросом с плакатом)   -  person Joseph Eames    schedule 13.02.2016
comment
Если кто-то делает глубокие ссылки на страницу, сервер подключается, и вы выполняете проверку подлинности на сервере. Если кто-то авторизован, он попадает в ваше приложение. Оказавшись в вашем приложении, они могут свободно перемещаться. Браузер и js не должны выполнять здесь проверки авторизации, это должен делать сервер.   -  person John Papa    schedule 14.02.2016
comment
Это звучит так просто, Джон. но это не так. Не обрабатывает тайм-ауты на стороне клиента. Не обрабатывает выход из системы на клиенте. Не обрабатывает приложения с разными уровнями аутентификации. или приложения, в которых некоторые приложения предварительно входят в систему, некоторые публикуются. Должен ли я лениво загружать половину приложения после входа в систему в момент входа в систему? И как мне отменить загрузку половины после входа в систему, когда они выходят из системы?   -  person Joseph Eames    schedule 14.02.2016
comment
Вы получаете любое значение, var url = this.parentRouter.lastNavigationAttempt, в URL??   -  person micronyks    schedule 24.02.2016


Ответы (3)


Для тех, кто найдет это, ответ теперь в Angular 2 — использовать «Guards» как часть нового маршрутизатора. См. документацию по Angular 2:

https://angular.io/docs/ts/latest/guide/router.html#!#guards

Базовая защита просто реализует «CanActivate» и может работать следующим образом:

import {Injectable} from "@angular/core";
import {CanActivate, Router} from "@angular/router";
import {AuthService} from "../services/auth.service";

@Injectable()
export class AuthGuard implements CanActivate {
    constructor(private authService:AuthService, private router:Router){}

    canActivate(){
        if(this.authService.isAuthenticated())
            return true;

        this.router.navigate(["/login"]);
        return false;
    }
}

Как вы можете видеть в этом примере, у меня есть AuthService, работающий где-то еще (реализация не важна), который может сообщить охраннику, прошел ли пользователь аутентификацию. Если они есть, верните true, и навигация произойдет как обычно. Если нет, мы возвращаем false и перенаправляем их на экран входа в систему.

person John Ackerman    schedule 29.06.2016
comment
Привет Джон, добро пожаловать в SO и спасибо за ваш ответ. Ответы только на код не рекомендуются, потому что ссылка может со временем измениться и стать недействительной, поэтому гораздо лучше предоставить полный ответ, который может стоять здесь сам по себе, со ссылкой в ​​качестве ссылки. Не могли бы вы отредактировать свой ответ с учетом этого? Спасибо еще раз! - person Tim Malone; 29.06.2016
comment
@JohnAckerman Но недостатком этого подхода по сравнению с подходом OP является то, что мы должны упомянуть эту защиту для всех путей, требуемых для аутентификации, поэтому дублирование и использование кода OP мы также можем сохранить последний предпринятый маршрут, а затем использовать его для перенаправления пользователя после входа в систему. успешный. - person lbrahim; 30.08.2016
comment
@ Ибрагим, не совсем так. Если у вас есть целый раздел (модуль?) сайта, который должен быть за охраной, то вы должны соответствующим образом структурировать свои маршруты. Вам нужен только охранник на родительском уровне. Если вы определяете маршрут /admin с дочерними элементами, только маршрут администратора нуждается в защите, и дочерние элементы наследуют его. - person John Ackerman; 01.09.2016

Вот обновленный пример использования AuthGuard с Angular 2 RC6.

Маршруты с домашним маршрутом, защищенные AuthGuard

import { Routes, RouterModule } from '@angular/router';

import { LoginComponent } from './login/index';
import { HomeComponent } from './home/index';
import { AuthGuard } from './_guards/index';

const appRoutes: Routes = [
    { path: 'login', component: LoginComponent },

    // home route protected by auth guard
    { path: '', component: HomeComponent, canActivate: [AuthGuard] },

    // otherwise redirect to home
    { path: '**', redirectTo: '' }
];

export const routing = RouterModule.forRoot(appRoutes);

AuthGuard перенаправляет на страницу входа, если пользователь не вошел в систему

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

@Injectable()
export class AuthGuard implements CanActivate {

    constructor(private router: Router) { }

    canActivate() {
        if (localStorage.getItem('currentUser')) {
            // logged in so return true
            return true;
        }

        // not logged in so redirect to login page
        this.router.navigate(['/login']);
        return false;
    }
}

Полный пример и рабочую демонстрацию вы можете найти на странице этот пост

person Jason Watmore    schedule 25.08.2016

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

Удачи.

person aberenyi    schedule 14.02.2016