はじめに (対象読者・この記事でわかること)
この記事は、JavaでWebアプリケーション開発を行っている方、Google Cloud Platformを利用している方、APIの認証・認可を実装したい方を対象としています。特に、Google Cloud Endpointsを使用して、特定のAPIエンドポイントを認証済みユーザーのみが実行できるようにする方法について解説します。この記事を読むことで、Google Cloud EndpointsとFirebase Authenticationを連携させたユーザー限定APIの実装方法、具体的なコード例、デプロイ手順を理解できます。また、実装中によく発生する問題とその解決策についても学べるため、実際の開発現場で即役立つ知識を得ることができます。
前提知識
この記事を読み進める上で、以下の知識があるとスムーズです。 - Javaの基本的な知識 - Google Cloud Platformの基本的な知識 - REST APIの基本的な知識 - Firebase Authenticationの基本的な知識
Google Cloud Endpointsとユーザー認証の概要
Google Cloud Endpointsは、Google Cloud上でAPIを簡単に作成・管理・デプロイできるサービスです。特にJavaを使用したバックエンドサービスとの連携に優れており、APIの仕様定義、クライアントライブラリの生成、モニタリングなどを自動化できます。
多くのWebアプリケーションでは、一部の機能やAPIを特定のユーザーのみに限定して提供する必要があります。例えば、個人データを取得するエンドポイントや、有料機能を利用するエンドポイントなどです。Google Cloud Endpointsでは、このような認証・認可要件を簡単に実装できます。
認証には通常、Firebase Authenticationを利用します。これにより、Googleアカウント、メールアドレス、電話番号などによるユーザー認証を簡単に実装できます。認証済みユーザーのみがアクセスできるエンドポイントでは、リクエストに含まれるIDトークンを検証することで、ユーザーの正当性を確認します。
特定エンドポイントをユーザー限定に実装する具体的な手順
ステップ1:Google Cloudプロジェクトのセットアップ
まず、Google Cloud Consoleで新しいプロジェクトを作成します。プロジェクト作成後、以下のAPIを有効にします: 1. Cloud Endpoints API 2. Cloud Trace API 3. Service Management API 4. Firebase Admin API
次に、プロジェクトに課金が有効になっていることを確認します。Cloud Endpointsを使用するには、課金が必須です。
Bash# gcloudコマンドラインツールを使用してプロジェクトを設定 gcloud config set project [YOUR_PROJECT_ID] gcloud services enable endpoints.googleapis.com gcloud services enable trace.googleapis.com gcloud services enable servicemanagement.googleapis.com gcloud services enable firebase.googleapis.com
ステップ2:Firebase Authenticationの有効化
Firebase Authenticationを有効にし、認証方法を設定します。ここではメール/パスワード認証を例に説明します。
- Firebase ConsoleでAuthenticationセクションに移動
- 「始める」ボタンをクリック
- 「メール/パスワード」を有効にする
Java// Firebase Admin SDKの初期化 FirebaseApp.initializeApp(new FirebaseOptions.Builder() .setCredential(FirebaseCredentials.getApplicationDefault()) .setDatabaseUrl("https://[YOUR_PROJECT_ID].firebaseio.com") .build());
ステップ3:Cloud Endpointsの設定
APIの仕様を定義するOpenAPI仕様ファイル(swagger.yaml)を作成します。このファイルでは、エンドポイントのパス、HTTPメソッド、パラメータ、リクエスト/レスポンス形式などを定義します。
Yamlswagger: '2.0' info: title: User Limited API description: API with user-limited endpoints version: 1.0.0 host: [YOUR_PROJECT_ID].cloudfunctions.net x-google-endpoints: - name: "[YOUR_PROJECT_ID].cloudfunctions.net" allowCors: true schemes: - https paths: /public: get: summary: Public endpoint operationId: publicEndpoint x-google-backend: address: https://[YOUR_REGION]-[YOUR_PROJECT_ID].cloudfunctions.net/publicFunction responses: '200': description: A successful response schema: type: string /private: get: summary: Private endpoint (user-limited) operationId: privateEndpoint x-google-backend: address: https://[YOUR_REGION]-[YOUR_PROJECT_ID].cloudfunctions.net/privateFunction security: - firebase: [] responses: '200': description: A successful response schema: type: string securityDefinitions: firebase: authorizationUrl: "" flow: "bearer" name: "Firebase" type: "apiKey" x-google-issuer: "https://securetoken.google.com/[YOUR_PROJECT_ID]" x-google-jwks_uri: "https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com" x-google-jwks: "https://www.googleapis.com/identitytoolkit/v3/relyingparty/publicKeys"
ステップ4:Javaバックエンドでの認証チェックの実装
Cloud Functions for Firebaseを使用して、Javaでバックエンドを実装します。認証が必要なエンドポイントでは、IDトークンを検証する処理を追加します。
Java// 公開エンドポイント(認証不要) public String publicEndpoint() { return "This is a public endpoint that anyone can access."; } // プライベートエンドポイント(認証必須) public String privateEndpoint(HttpServletRequest request) throws Exception { // リクエストからAuthorizationヘッダーを取得 String idToken = request.getHeader("Authorization").replace("Bearer ", ""); // IDトークンを検証 FirebaseToken decodedToken = FirebaseAuth.getInstance().verifyIdToken(idToken); String uid = decodedToken.getUid(); // 検証成功時の処理 return "Hello, " + uid + "! This is a private endpoint only authenticated users can access."; }
ステップ5:特定エンドポイントのユーザー限定設定
OpenAPI仕様ファイルで、特定のエンドポイントに認証要件を設定します。securityプロパティを使用して、エンドポイントごとに認証の有無を指定します。
Yaml# 公開エンドポイント(認証不要) /public: get: # ... その他の設定 ... # プライベートエンドポイント(認証必須) /private: get: security: - firebase: [] # このエンドポイントではFirebase認証を必須にする # ... その他の設定 ...
ハマった点やエラー解決
問題1:IDトークンの検証で「Invalid ID token」エラーが発生
原因:リクエストヘッダーに含まれるIDトークンが無効、期限切れ、または不正な形式である。
解決策: 1. クライアント側でIDトークンが正しく取得されているか確認 2. トークンの有効期限を確認(デフォルトでは1時間) 3. トークンが改ざんされていないか検証
Java// トークン検証時のエラーハンドリング try { FirebaseToken decodedToken = FirebaseAuth.getInstance().verifyIdToken(idToken); String uid = decodedToken.getUid(); // ユーザーIDを使用した処理 } catch (FirebaseAuthException e) { // トークンが無効な場合 response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); return "Invalid ID token"; }
問題2:CORSエラーが発生
原因:Cloud Functionsのデプロイ時にCORS設定が正しく行われていない。
解決策:
1. Cloud Functionsのデプロイ時にCORSヘッダーを設定
2. OpenAPI仕様ファイルでallowCors: trueを設定
Java// CORS対応のフィルター public class CorsFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletResponse httpResponse = (HttpServletResponse) response; httpResponse.setHeader("Access-Control-Allow-Origin", "*"); httpResponse.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); httpResponse.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization"); if ("OPTIONS".equalsIgnoreCase(((HttpServletRequest) request).getMethod())) { httpResponse.setStatus(HttpServletResponse.SC_OK); } else { chain.doFilter(request, response); } } // ... 他のメソッドは省略 ... }
問題3:認証済みユーザーでも「403 Forbidden」エラー
原因:Cloud Endpointsのバックエンド設定で認証情報が正しく渡されていない。
解決策:
1. OpenAPI仕様ファイルのx-google-backend設定を確認
2. バックエンド関数でリクエストヘッダーが正しく渡されているか確認
Yaml# 正しいx-google-backendの設定 x-google-backend: address: https://[YOUR_REGION]-[YOUR_PROJECT_ID].cloudfunctions.net/privateFunction jwt_audience: [YOUR_PROJECT_ID] jwt_headers: id_token: Authorization
まとめ
本記事では、Google Cloud Endpointsを使用して特定のAPIエンドポイントを認証済みユーザーのみが実行できるようにする方法について解説しました。
- Google CloudプロジェクトとFirebase Authenticationのセットアップ
- OpenAPI仕様ファイルでの認証要件の定義
- JavaバックエンドでのIDトークン検証の実装
- CORSエラーなどの問題解決策
この記事を通して、Google Cloud Platform上で安全なAPIを構築するための具体的な知識を得られたことと思います。今後は、より高度な認可ロール(管理者、一般ユーザーなど)の実装や、リクエストレート制限などのセキュリティ対策についても記事にする予定です。
参考資料
- Google Cloud Endpoints公式ドキュメント
- Firebase Authentication公式ドキュメント
- Cloud Functions for Firebase公式ドキュメント
- OpenAPI Specification
