Проверьте, вошел ли пользователь в систему на любом изменении страницы в Angular 2

медленно, но верно прогрессирует с Angular2. И вот теперь передо мной встал следующий вызов. Я хочу проверить, вошел ли пользователь в систему или нет на каждой странице изменения (другими словами, при загрузке каждого компонента). Конечно, я могу реализовать интерфейс OnInit в каждом из них, но это запах кода.

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

Я использую эту библиотеку (https://auth0.com/blog/2015/11/10/introducing-angular2-jwt-a-library-for-angular2-authentication/) для входа на основе JWT и у меня уже есть хороший класс обслуживания, который инкапсулирует все функции, связанные с аутентификацией. Таким образом, фактическая проверка того, где или нет пользователь вошел в систему, уже выполнена и протестирована.

спасибо,

3 ответов


если вы используете маршрутизацию (и вроде бы так, поскольку вы говорите: "на каждой странице"), вы можете использовать несколько вещей:

  • создайте пользовательский маршрутизатор-розетку (подкласс RouterOutlet), который проверяет аутентификацию с его activate метод называется. В этом случае у вас может быть что-то глобальное. Что-то вроде этого:--7-->

    @Directive({
      selector: 'auth-outlet'
    })
    export class AuthOutlet extends RouterOutlet {
      (...)
    
      activate(oldInstruction: ComponentInstruction) {
        var url = this.parentRouter.lastNavigationAttempt;
        if (isAuthenticated()) {
          return super.activate(oldInstruction);
        } else {
          (...)
        }
      }
    }
    

    см. этот вопрос для получения более подробной информации:

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

  • что-то также можно сделать на уровне RouterLink, чтобы показать / скрыть ссылки маршрута. В этом случае можно применить роли к этим ссылкам на основе связанной конфигурации маршрута и подсказок текущего пользователя. См. этот вопрос Для больше подробности:

это также может быть обработано в HTTP-перехватчике (класс, который расширяет Http один). В этом случае при выполнении запроса можно подключить некоторые проверки подлинности:

@Injectable()
export class CustomHttp extends Http {
  constructor(backend: ConnectionBackend, defaultOptions: RequestOptions) {
    super(backend, defaultOptions);
  }

  request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
    console.log('request...');
    if (isAuthenticated()) {
      return super.request(url, options).catch(res => {
        // do something
      });        
    } else {
      // Redirect to login page
      // Or throw an exception: return Observable.throw(new Error(...));
    }
  }

  (...)
}

см. этот вопрос для получения более подробной информации:


я показываю вам простую реализацию с Angular2. Вы можете воспользоваться @CanActivate крюк, как показано удар, чтобы проверить, является ли пользователь loggedIn или нет с функция isLoggedIn возвращает обещание.

Примечание: ниже реализация должна проверить, является ли пользователь loggedIn перед доступом к любому компоненту или нет. Я надеюсь, что с помощью некоторых модификаций вы сможете достичь того, чего хотите иметь.

Auth.ТС

import {Observable} from 'rxjs/Observable';

export class Auth {
  constructor() {
    this.loggedIn = false;
  }

  login() {
    this.loggedIn = true;
  }

  logout() {
    this.loggedIn = false;
  }

  check() {
    return Observable.of(this.loggedIn);
  }
}

isLoggedIn.ТС

import {Injector} from 'angular2/core';
import {appInjector} from './appInjector';
import {Auth} from './Auth';
import {Router, ComponentInstruction} from 'angular2/router';

export const isLoggedIn = (next: ComponentInstruction, previous: ComponentInstruction) => {
    let injector: Injector = appInjector(); // get the stored reference to the injector
    let auth: Auth = injector.get(Auth);
    let router: Router = injector.get(Router);

  // return a boolean or a promise that resolves a boolean
    return new Promise((resolve) => {
      auth.check()
          .subscribe((result) => {
                    if (result) {
                        resolve(true);
                    } else {
                        router.navigate(['/Login']);
                        resolve(false);
                    }
                });
  });
};

appInjector.ТС

import {Injector} from 'angular2/core';

let appInjectorRef: Injector;
export const appInjector = (injector?: Injector):Injector => {
    if (injector) {
      appInjectorRef = injector;
    }

    return appInjectorRef;
};

somecomponent.ТС

import {Component, View,ViewChild} from 'angular2/core';
import {CanActivate} from 'angular2/router';
import {isLoggedIn} from './isLoggedIn';

@Component({
  selector: 'some',
  template: 'some text'
})
@CanActivate((next: ComponentInstruction, previous: ComponentInstruction) => {
  return isLoggedIn(next, previous);  // this will tell whether user is loggedIn or not. 
})
export class Protected {
}

boot.ТС

.
.
import { provide, ComponentRef } from 'angular2/core';
import { appInjector } from './app-injector';
.
.
bootstrap(AppComponent, [...]).then((appRef: ComponentRef) => {
  // store a reference to the application injector
  appInjector(appRef.injector);
});

есть два способа ограничить доступ к Custom Router Outlet и CanActivate Decorator показано и реализовано в этой большой статье аутентификация в Angular 2


Я думаю, что расширение RouterOutlet является распространенным способом достичь этого

пример опубликован некоторое время назад в Gitter by капитан Кодман (Не проверял еще)

  import {Directive, Injector, Attribute, ElementRef, DynamicComponentLoader} from 'angular2/core';
  import {Router, RouteData, RouterOutlet, RouteParams, Instruction, ComponentInstruction} from 'angular2/router';

  /*
    Example implementation

    Given a route:
    @RouteConfig([
    { path: '/thing/:id', component: ThingComponent, name: 'Thing', data: { public: false, roles:['thinger'] } }
    ])

    authorize(instruction: ComponentInstruction):boolean {
      // simplest case - route is public
      if (<boolean>instruction.routeData.data['public']) {
        return true;
      }

      // if not public then we at least need an authenticated user
      if (this.isAuthenticated()) {
        var routeRoles = <any[]>instruction.routeData.data['roles'];
        var userRoles = <string[]>this.roles();

        // no roles required for route = user just needs to be authenticated
        var authorized = routeRoles.length === 0 || routeRoles.some(routeRole => userRoles.indexOf(routeRole) >= 0);

        return authorized;
      }

      return false;
    }
  */
  export abstract class IAuthService {
    abstract isAuthenticated():boolean;
    authorize(instruction: ComponentInstruction, params:any):boolean {
      // authorized if route allows public access or user is authenticated
      return this.isAuthenticated() || <boolean>instruction.routeData.data['public']
    }
  }
@Directive({selector: 'secure-outlet'})
  export class SecureRouterOutlet extends RouterOutlet {
    signin:string;
    unauthorized:string;
    injector:Injector;

    private parentRouter: Router;
    private authService: IAuthService;

    constructor(_elementRef: ElementRef, _loader: DynamicComponentLoader,
                _parentRouter: Router, @Attribute('name') nameAttr: string,
                authService:IAuthService,
                injector:Injector,
                @Attribute('signin') signinAttr: string,
                @Attribute('unauthorized') unauthorizedAttr: string) {
      super(_elementRef, _loader, _parentRouter, nameAttr);
      this.parentRouter = _parentRouter;
      this.authService = authService;
      this.injector = injector;
      this.signin = signinAttr;
      this.unauthorized = unauthorizedAttr;
    }

    activate(nextInstruction: ComponentInstruction): Promise<any> {
      var params = this.getAllRouteParams(this.injector);
      var isAuthorized = this.authService.authorize(nextInstruction, params);

      if (isAuthorized) {
        return super.activate(nextInstruction);
      }

      if (this.authService.isAuthenticated()) {
        var ins = this.parentRouter.generate([this.unauthorized]);
        return super.activate(ins.component);
      } else {
        var ins = this.parentRouter.generate([this.signin,{url:location.pathname}]);
        return super.activate(ins.component);
      }
    }

    reuse(nextInstruction: ComponentInstruction): Promise<any> {
      return super.reuse(nextInstruction);
    }

    getAllRouteParams(injector) {
      let params = null;
      while(injector) {
        const routeParams = injector.getOptional(RouteParams);
        if (routeParams) {
          if (params === null) {
            params = {};
          } else {
            params = Object.create(params);
          }

          Object.assign(params, routeParams.params);
        }
        injector = injector.parent;
      }
      return params;
    }
  }