ゆっくりではあるが確実にAngular2で進歩している。そして今、私は次の挑戦に直面しました。ユーザーがすべてのページ変更で(つまり、すべてのコンポーネントのロードで)ログインしたかどうかを確認したいと思います。もちろん、私はそれらすべてにOnInitインターフェースを実装できますが、それはコードのにおいです。
アプリのすべてのページで必要なものを実行する効率的な方法はありますか?このタスクを処理する方法のベストプラクティスに関する他の提案を聞きたいです。
私はこのライブラリ( https://auth0.com/blog/2015/11/10/introducing-angular2-jwt-a-library-for-angular2-authentication/ )をjwtベースのログインに使用しています認証に関連するすべての機能をカプセル化するNiceサービスクラスを既に持っています。そのため、ユーザーがログインしているかどうかの実際のチェックは、すでに行われてテストされています。
おかげで、
ルーティングを使用する場合(そして、「すべてのページ変更時」と言うのでそうであるように思われる場合)、いくつかのことを活用できます。
RouterOutlet
メソッドが呼び出されて認証をチェックするカスタムルーターアウトレット(activate
のサブクラス)を作成します。この場合、グローバルなものを作成できます。そんな感じ:
@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(...));
}
}
(...)
}
詳細については、この質問を参照してください:
RouterOutletを拡張することはこれを達成するための一般的な方法だと思います
CaptainCodeman によってGitterにしばらく前に投稿された例(まだ自分でテストしていない)
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;
}
}
Angular2を使用した簡単な実装を紹介します。以下に示すように@ CanActivateフックを利用して、ユーザーがログインしているかどうかをisLoggedIn functionで確認すると、promiseが返されます。
[〜#〜] note [〜#〜]:以下の実装では、コンポーネントにアクセスする前に、ユーザーがloggedIn
かどうかを確認します。私はいくつかの変更によってあなたが望むものを達成できることを願っています。
Auth.ts
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.ts
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.ts
import {Injector} from 'angular2/core';
let appInjectorRef: Injector;
export const appInjector = (injector?: Injector):Injector => {
if (injector) {
appInjectorRef = injector;
}
return appInjectorRef;
};
somecomponent.ts
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.ts
.
.
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);
});
アクセスを制限するには2つの方法がありますCustom Router Outlet
およびCanActivate Decorator
この素晴らしい記事に表示および実装されています Authentication in Angular 2
これは私がやったことです、app.routing.tsのcanActiveプロパティを使用しました
{
path: 'dashboard',
loadChildren: './dashboard',
canActivate:[AuthGuard]
},
以下の5分のビデオチュートリアルに従ってください
https://www.youtube.com/watch?v=0Qsg8fyKwO4
注:このソリューションはAngular 4