Проверьте, вошел ли пользователь в систему на любом изменении страницы в 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;
}
}