Angularアプリケーションのセキュリティを強化!HTTPインターセプターで認証を実装する方法
Angularアプリケーションに複数のHTTPインターセプターを追加する方法
HTTPインターセプターとは?
HTTPインターセプターは、Angularアプリケーションが発行するすべてのHTTPリクエストとレスポンスを傍受して処理できるサービスです。リクエストを変更したり、レスポンスからデータを抽出したり、エラーを処理したりできます。
複数のHTTPインターセプターを追加する利点
- 拡張性: 新しい要件が発生した場合は、新しいインターセプターを作成するだけで対応できます。
- 再利用可能なロジック: 共通のタスクを実行するインターセプターを作成することで、コードの重複を排除できます。
- モジュラー設計: インターセプターを個別に作成して管理することで、コードをより整理しやすくなり、再利用しやすくなります。
- インターセプターを作成する: 各インターセプターは、
implements HttpInterceptor
インターフェースを実装するクラスとして定義します。intercept
メソッドは、リクエストまたはレスポンスを処理するために使用されます。 - インターセプターをプロバイダーとして登録する:
AppModule
または他のモジュールで、HTTP_INTERCEPTORS
トークンを使用してインターセプターをプロバイダーとして登録します。インターセプターの配列を指定する必要があります。順序は重要です。最初に登録されたインターセプターが最初に呼び出され、その後に続くインターセプターが呼び出されます。
例
以下の例では、認証トークンをすべてのリクエストに追加するインターセプターと、ログにリクエストとレスポンスを出力するインターセプターを作成します。
// auth.interceptor.ts
import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const authToken = localStorage.getItem('authToken');
if (authToken) {
req = req.clone({ headers: req.headers.set('Authorization', `Bearer ${authToken}`) });
}
return next.handle(req);
}
}
// logging.interceptor.ts
import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable()
export class LoggingInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
console.log('Request:', req);
const started = Date.now();
return next.handle(req).pipe(
tap(event => {
if (event.type === HttpEventType.Response) {
console.log(`Response ${event.status}: ${event.body} in ${Date.now() - started} ms`);
}
})
);
}
}
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { AppComponent } from './app.component';
import { AuthInterceptor } from './auth.interceptor';
import { LoggingInterceptor } from './logging.interceptor';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
HttpClientModule
],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: AuthInterceptor,
multi: true
},
{
provide: HTTP_INTERCEPTORS,
useClass: LoggingInterceptor,
multi: true
}
],
bootstrap: [AppComponent]
})
export class AppModule { }
この例では、AuthInterceptor
が最初に呼び出され、リクエストに認証トークンを追加します。次に、LoggingInterceptor
が呼び出され、リクエストとレスポンスをコンソールにログに出力します。
このコードは、基本的な例です。実際のアプリケーションでは、より複雑なロジックを実装する必要がある場合があります。
- [Angular HTTPインターセプター](
import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const authToken = localStorage.getItem('authToken');
if (authToken) {
req = req.clone({ headers: req.headers.set('Authorization', `Bearer ${authToken}`) });
}
return next.handle(req);
}
}
logging.interceptor.ts
import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable()
export class LoggingInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
console.log('Request:', req);
const started = Date.now();
return next.handle(req).pipe(
tap(event => {
if (event.type === HttpEventType.Response) {
console.log(`Response ${event.status}: ${event.body} in ${Date.now() - started} ms`);
}
})
);
}
}
app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { AppComponent } from './app.component';
import { AuthInterceptor } from './auth.interceptor';
import { LoggingInterceptor } from './logging.interceptor';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
HttpClientModule
],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: AuthInterceptor,
multi: true
},
{
provide: HTTP_INTERCEPTORS,
useClass: LoggingInterceptor,
multi: true
}
],
bootstrap: [AppComponent]
})
export class AppModule { }
追加の例
以下の例では、エラー処理を行うためのインターセプターを追加する方法を示します。
// error.interceptor.ts
import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpResponse } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
@Injectable()
export class ErrorInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(req).pipe(
catchError(error => {
if (error.status === 401) {
// 認証エラーを処理する
return throwError(error);
} else {
// その他のエラーを処理する
const errorMessage = `Error ${error.status}: ${error.message}`;
console.error(errorMessage);
return throwError(errorMessage);
}
})
);
}
}
このインターセプターは、next.handle
メソッドから返されるObservableを傍受します。エラーが発生すると、catchError
オペレーターを使用して処理されます。
このコードをAppModule
のproviders
配列に追加して、アプリケーションで使用できます。
{
provide: HTTP_INTERCEPTORS,
useClass: ErrorInterceptor,
multi: true
}
RouterModule
には、認証ガードと認証ルートを設定するための機能が用意されています。認証ガードは、ユーザーが認証されていない場合にリダイレクトしたり、アクセスを拒否したりするために使用できます。認証ルートは、認証されたユーザーのみがアクセスできるルートを定義するために使用できます。
この方法は、シンプルな認証要件を持つアプリケーションに適しています。
NgAuthzを使用する
NgAuthzは、Angularアプリケーションにおけるアクセス制御を管理するためのライブラリです。ロールベースのアクセス制御(RBAC)を実装し、ユーザーに特定のアクセス許可を付与することができます。
カスタム認証ソリューションを使用する
独自の認証ソリューションを構築することもできます。これは、完全な制御が必要な場合や、他のライブラリでは提供されていない機能が必要な場合に適しています。
どの方法を選択するべきですか?
最適な方法は、アプリケーションの要件によって異なります。
- 完全な制御が必要な場合、または他のライブラリでは提供されていない機能が必要な場合は、カスタム認証ソリューションを構築する必要があります。
- より複雑なアクセス制御要件の場合は、NgAuthzを使用するのが良いでしょう。
- シンプルな認証要件の場合は、
RouterModule
を使用するのが良いでしょう。
- クロスサイトスクリプティング(XSS)やクロスサイトリクエストフォージャー(XSRF)などの一般的な脆弱性に対してアプリケーションを保護してください。
- すべてのAPIエンドポイントが適切に保護されていることを確認してください。
- ユーザーが長期間非アクティブになっている場合は、トークンの有効期限を切らせるようにしてください。
- ログアウト時にトークンを削除することを忘れないでください。
- トークンベースの認証を使用している場合は、HTTPインターセプターを使用して、すべての要求に認証トークンを追加することを検討してください。
angular http interceptor