認証されていないユーザーがまったくアクセスできないアプリケーションを構築しています。
LoggedInGuard
を作成しましたが、ルーター構成内のeveryルートにcanActivate: [LoggedInGuard]
を追加する必要があります(LoginComponent
を除く)。
これを機能させるためのより良い方法はありますか?
私のファイル/モジュールのレイアウトは次のようになります。
app/
AppModule
AppRoutingModule
AppComponent
authentication/
AuthenticationModule
AuthenticationRoutingModule
LoginComponent
contacts/
ContactsModule
ContactsRoutingModule
ContactListComponent
users/
UsersModule
UsersRoutingModule
UserEditComponent
...
たぶん、2つの別々のルーティングスペース(1つはログイン用、もう1つはアプリの残りの部分用)を作成し、アプリの残りの部分にのみガードを適用することが可能です。 )一部?
簡単な解決策があるといいのですが。
前もって感謝します!
私はもっと論理的な方法でそれをしていると思います。意見だと思います。アプリケーションをsecured pages
とpublic pages
で区切ります。セットごとにテンプレートを使用しています。したがって、public component
とsecure component
は、guard
をsecure template
に配置します。
保護が必要なフルルートに[Guard]
を追加していることを確認してください。
したがって、ルートを確保するときに、親をapp.routing.ts
に追加します
const APP_ROUTES: Routes = [
{ path: '', redirectTo: '/home', pathMatch: 'full', },
{ path: '', component: PublicComponent, data: { title: 'Public Views' }, children: PUBLIC_ROUTES },
{ path: '', component: SecureComponent, canActivate: [Guard], data: { title: 'Secure Views' }, children: SECURE_ROUTES }
];
export const routing = RouterModule.forRoot(APP_ROUTES);
この行に注意してください。
{ path: '', component: SecureComponent, canActivate: [Guard], data: { title: 'Secure Views' }, children: SECURE_ROUTES }
だから私は2つのレイアウトを作成します
/ public /すべてのパブリックコンポーネント
/ public/public.routes.ts
/ secure /すべてのセキュアコンポーネント
/ secure/secure.routes.ts
安全なルート
これらのルートはテンプレートの親によって処理されるため、Guard
は必要ないことに注意してください。
export const SECURE_ROUTES: Routes = [
{ path: '', redirectTo: 'overview', pathMatch: 'full' },
{ path: 'items', component: ItemsComponent },
{ path: 'overview', component: OverviewComponent },
{ path: 'profile', component: ProfileComponent },
];
app.routing.tsのメインルート
const APP_ROUTES: Routes = [
{ path: '', redirectTo: '/home', pathMatch: 'full', },
{ path: '', component: PublicComponent, data: { title: 'Public Views' }, children: PUBLIC_ROUTES },
{ path: '', component: SecureComponent, canActivate: [Guard], data: { title: 'Secure Views' }, children: SECURE_ROUTES }
];
export const routing = RouterModule.forRoot(APP_ROUTES);
そして、ディレクトリ/ layoutsに、次のようなレイアウトを作成します。
/ layouts/secure.component.ts
/ layouts/secure.component.html
/ layouts/public.component.ts
/ layouts/public.component.html
すべてがレイアウトpublic
またはsecure
を介してルーティングされ、[Guard]
は安全です。
次に、ローカルストレージ内のトークンを使用して認証を処理します。
@Injectable()
export class Guard implements CanActivate {
constructor(protected router: Router, protected auth: Auth ) {}
canActivate() {
if (localStorage.getItem('access_token')) {
// logged in so return true
return true;
}
// not logged in so redirect to login page
this.router.navigate(['/home']);
return false;
}
}
このようにアプリを設定したら、セキュリティで保護する必要のあるすべてのルートをセキュアディレクトリに配置し、パブリックルートをパブリックに配置します。次に、それぞれのディレクトリにあるpublic.routes.tsファイルまたはsecure.routes.tsファイルにルートを作成します。
ガードをルーターイベントリスナーに移動することで、複数のモジュールにまたがるグローバルガードのセットを提供することができました。
すべてのリクエストに対してイベントリスナーを起動させるために、AppComponentに挿入しました。
以下の両方の例で、個々のルートにカスタムガードを追加することができ、それらは引き続き機能することに注意してください。
警備員なし
ガードの使用を削除し、代わりにイベントリスナーにロジックを直接実装できます。
import { Component, OnInit } from '@angular/core';
import { Router, RoutesRecognized } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/filter';
// I use a service to keep track of the authentication ticket.
// Replace this with whatever mechanism you use.
import { AuthenticationService } from './_services/index';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
constructor(
private router: Router,
private authService: AuthenticationService
) {}
ngOnInit() {
this.router.events
.filter(event => event instanceof RoutesRecognized)
.subscribe((event: RoutesRecognized) => {
const url = event.urlAfterRedirects;
// Public URLs don't need any kind of authorization.
if (url === '/public' || url.startsWith('/public/') || url.startsWith('/public?')) {
return;
}
// Everything else must be authenticated.
if (!this.authService.isAuthenticated()) {
// Allow for the login page to redirect back to the originally
// requested page.
this.router.navigate(['/public/login'], { queryParams: { returnUrl: state.url } });
}
});
}
}
/public
のサブページに渡されたリクエストは関係なく通過しますが、他のリクエストには認証が必要です。そうでない場合、/public/login
にリダイレクトされます。
リダイレクトページが保護領域にないように注意してください。そうしないと、ルーターが無限ループに入ります。
警備員付き
以下の実装は、既存のガードを再利用する方法を示しています。これは、それらを保持する必要がある場合、またはコードをよりクリーンにする場合のみです。
import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute, RoutesRecognized, CanActivate } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/filter';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/mergeMap';
// Reused guards.
import { AdminGuard, AuthGuard } from './_guards/index';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
constructor(
private route: ActivatedRoute,
private router: Router,
private adminGuard: AdminGuard,
private authGuard: AuthGuard
) {}
ngOnInit() {
this.router.events
.filter(event => event instanceof RoutesRecognized)
.subscribe((event: RoutesRecognized) => {
// Public pages don't require authentication.
if (this.isSubPage(event, '/public')) {
return;
}
// All other requests MUST be done through an
// authenticated connection. The guard performs
// the redirection for us.
if (!this.callCanActivate(event, this.authGuard)) {
return;
}
// Administration pages require additional restrictions.
// The guard performs the redirection for us.
if (this.isSubPage(event, '/admin')) {
if (!this.callCanActivate(event, this.adminGuard)) {
return;
}
}
});
}
callCanActivate(event: RoutesRecognized, guard: CanActivate) {
return guard.canActivate(this.route.snapshot, event.state);
}
isSubPage(event: RoutesRecognized, parent: string) {
const url = event.urlAfterRedirects;
return (url === parent
|| url.startsWith(parent + '/')
|| url.startsWith(parent + '?'));
}
}
この例は上記の例と同じですが、/admin
領域の保護が追加されており、ユーザーが管理者権限も持っていることが保証されます。