Amazon Cognitoで構築するスケーラブルなWebアプリケーション① - セッションベース認証とトークンベース認証

記事タイトルとURLをコピーする

この記事は約6分で読めます。

こんにちは。
アプリケーションサービス部、DevOps担当の兼安です。

今回からAmazon Cognitoについての記事を書いていきます。
目標は、Amazon Cognitoを使ってスケーラブルなWebアプリケーションを構築することとし、何回かに分けて説明します。
1回目の今回は、認証方式がスケーラブルかどうかに関係があることを説明します。

本記事のターゲット

Webアプリケーションの開発経験があり、今後、Webアプリケーションをスケーラブルにしたい方を対象としています。
記事中にロードバランサー(=ALB)やAmazon EC2などが出てきますが、これらの説明は割愛していますので、AWSのコンピューティングサービスやデータベースサービスの知識があることが前提となります。

Webアプリケーションにおけるスケーラブルとは

最初に、Webアプリケーションにおけるスケーラブルとは何かを考えていきます。
Amazon EC2で稼働しているWebアプリケーションを例に考えてみます。
1つのEC2インスタンスでWebサーバーとデータベースの役割を両方担っているとします。
アクセスが増えて高負荷になった場合、このEC2インスタンスのサイズを大きくすることで対応はできますが、自動で行うのは難しいです。
一般的にこの状態はスケーラブルとは言われません。

1台のサーバーに複数の役割を担っている構成

ここから、Webサーバーとデータベースを分離して、Webサーバーを複数台にします。
その上でWebサーバーの前段にロードバランサー(ALB)を配置します。
このような構成にすると、Webサーバーのオートスケーリングが選択可能になります。
オートスケーリングを使用すると、アクセスの増減に応じてWebサーバーの台数を自動で増減させることができます。

ロードバランサーを駆使し、WEBサーバーを複数台にしている構成

この構成図だと、まだデータベースが1台しかないので、データベースがボトルネックになり得ますが、Webサーバーについてはスケーラブルであると言えます。

セッションベース認証

Webアプリケーションにおいて、ユーザーの認証を行う方法はいくつかあります。
その一つがセッションベース認証です。

セッションベース認証において、認証が必要なページを参照する場合、以下のような流れになります。

セッションベース認証は、ユーザーが認証されると、サーバー側はセッションIDを発行します。
一般的には、このセッションIDをCookieに保存しておき、ユーザーがページ遷移するたびにCookieを送信して、サーバー側でセッションIDを検証します。
検証の結果、セッションIDが有効であれば、ユーザーは認証済みとして扱われ、認証が必要なページが表示されます。

セッションベース認証とスケーラビリティ

このセッションベース認証を成立させるには、サーバー側でセッションを保存しておく必要があります。
この時、セッションを保存する場所によって、スケーラブルかどうかが変わります。
例えば、Webサーバーの中でセッションを保存している場合、以下のような問題が発生します。

セッションベース認証の問題

ロードバランサーに複数台のWebサーバーがあるとします。
最初に1台目のサーバーに振られて、ログイン。
次に2台目のサーバーに振られた場合、セッションが共有されていないため、ログイン状態が維持されません。

この課題を解決するためには、以下のような方法があります。

  • ロードバランサーのスティッキーセッションを有効にする
  • セッションをWebサーバーの外部に保存する

スティッキーセッションとセッションの外部保存

スティッキーセッションとは、ロードバランサーなどの機能の1つで、同じクライアントからのリクエストを常に同じサーバーに送る機能です。
Application Load Balancer(ALB)には、クッキーを使用したスティッキーセッション機能があります。

docs.aws.amazon.com

これを利用すると、あるクライアントがログインすると、そのクライアントからのリクエストは常に同じWebサーバーに送られるため、セッション切れが発生しません。
しかし、この方法ではロードバランサーの負荷分散機能の効力を発揮しきれません。

この問題を軽減するため、セッションをWebサーバーの外部に保存する方法があります。
主要なWebフレームワークには、セッションを外部に保存するための仕組みが用意されています。
例えば、Laravelでは、セッションをデータベースに保存することができます。

readouble.com

database - セッションをリレーショナルデータベースへ保存します memcached/redis - セッションをこれらの高速なキャッシュベースの保存域へ保存します dynamodb - セッションをAWS DynamoDBへ保存します

このように、セッションを外部に保存することで、Webサーバーのスケーラビリティを高めることができます。

DynamoDBにセッションを保存する場合、以下のような流れになります。

%%{
  init: {
    'theme': 'base',
    'themeVariables': {
      'textColor': 'white'
    }
  }
}%%
sequenceDiagram
    participant Client
    participant Server
    participant DynamoDB

    Client->>Server: POST /login (ユーザー名・パスワード)
    Server-->>Server: 認証処理
    Server->>DynamoDB: セッション情報を保存 (セッションID, ユーザー情報)
    DynamoDB-->>Server: セッション保存完了
    Server->>Client: セッションIDをセット (Set-Cookie)
    
    Note over Client: 認証成功後、セッションID保持
    Note over DynamoDB: 認証成功後、セッション情報を管理

    Client->>Server: GET /protected-resource (Cookie: セッションID)
    Server->>DynamoDB: セッションIDを参照しセッション情報を取得
    Server-->>Server: セッションの有効期限を確認
    DynamoDB-->>Server: セッション情報を返却
    Server->>Client: リソース提供

トークンベース認証

今度は、トークンベース認証について説明します。
トークンベース認証とは、トークンと呼ばれる文字列を用いて認証を行う方法です。
トークンは暗号署名を検証することで有効性を確認します。

トークンベース認証において、認証が必要なページを参照する場合、以下のような流れになります。

%%{
  init: {
    'theme': 'base',
    'themeVariables': {
      'textColor': 'white'
    }
  }
}%%
sequenceDiagram
    participant Client
    participant Server

    Client->>Server: POST /login (ユーザー名・パスワード)
    Server-->>Server: 認証処理
    Server->>Client: アクセストークンを返却 (JSONレスポンス)

    Note over Client: 認証成功後、アクセストークン保持

    Client->>Server: GET /protected-resource (Authorization: Bearer アクセストークン)
    Server-->>Server: アクセストークンを検証、改ざん有無と有効期限を確認
    Server->>Client: リソース提供

セッションを外部保存する方法と比較すると、違いが少し分かりやすくなります。
セッションベース認証がセッションIDに該当するセッションデータの有無と有効期限で認証可否を判断するのに対し、トークンベース認証は、トークンの有効性をロジックによる書名の検証によって判断するため、セッションデータを保存する必要がありません。
したがって、セッションベース認証よりもスケーラビリティを確保しやすいと言えます。

JWT認証

JWT(JSON Web Token)認証は、トークンベース認証の一つです。
RFCによって定義されたオープンスタンダードで、JSON形式で情報をやり取りするための軽量で自己完結型の方式です。

JWT認証はWebアプリケーションにおいて、広く利用されている認証方式で、その理由は以下のような特徴があるためです。

  • JWTはHTTPヘッダーに付与して使用できるため、Webブラウザ、モバイルアプリ、API通信などで同じ方法で認証できます。
  • JWTはBase64エンコードされたJSONペイロードにユーザー情報を保持します。 例えば、user_id や role、exp(有効期限)などの情報を埋め込むことができます。
  • JWTは署名付きで改ざん検出が可能です
  • OAuth2.0やOpenID Connectなどの認証プロトコルで利用されています。

このJWT認証は、Amazon Cognitoでも利用できます。
Amazon Cognitoは、ユーザーの認証と認可を管理するサービスです。
本記事の途中で、スケーラビリティを確保するために、セッション情報を外部に保存する方法を触れました。
Amazon Cognitoを使うと、そもそも認証と認可まわりをWebアプリケーションから分離することができます。
Webアプリケーションは、Amazon Cognitoに対して認証を行い、認証が成功すると、アクセストークンを取得できます。
このアクセストークンがJWTとなります。

次の記事ではWebアプリケーションにAmazon Cognitoを導入する方法を説明します。
よろしければ次の記事もご覧ください。

blog.serverworks.co.jp

兼安 聡(執筆記事の一覧)

アプリケーションサービス部 DS3課所属
2024 Japan AWS Top Engineers (Database)
2024 Japan AWS All Certifications Engineers
2025 AWS Community Builders
Certified ScrumMaster
PMP
広島在住です。今日も明日も修行中です。