Skip to content

アクセス制御

関連: 全体構成 / データ / アプリの使い方

制御は 2 段である。 手前が Cloudflare Access(誰がアプリに入れるか)、奥が Worker がメールを読む処理(入った人をアプリがどう扱うか)である。

レシピ帳そのものは、入った人のあいだで共有する。 ユーザごとに壁を立てる対象は、プロフィールとお気に入りだけである。

スキーマのコメントも「Recipes are a shared household book」と書いてある。 「ログインした人は自分のレシピだけ見える」という作りではない。

段 1: 入場(Cloudflare Access)

本番の想定は、カスタムドメイン home.ntatsuya.com の前に Access アプリケーションを置くことである。 IdP は Google である。許可するメールを Access のポリシーに書く。

いま README と wrangler.jsonc が前提にしている許可メールは coptis923@gmail.com のみである。 アプリのコードに許可リストは無い。 誰を通すかは Cloudflare Zero Trust 側の設定が正である。

Access を通ったリクエストには、Cloudflare が Cf-Access-Authenticated-User-Email を付ける。 Worker はこのヘッダだけを信じる。 クライアントがメールを送る項目は無い。

世帯の別の人を足すときは、Access の許可メールにその Google アカウントを追加する。 アプリのデプロイは不要である。 追加した人は、既存のコーヒー帳と料理帳を同じ権限で読めて、編集できる。

Access を外すと共有帳がむき出しになる

Worker は「Access を通った人」を区別するだけで、「このレシピの持ち主か」は見ない。 許可メールを増やした瞬間から、その人は全レシピを消せる。 公開インターネット向けの会員制アプリではない。

*.workers.dev(home-kitchen.coptis923.workers.dev)に Access を付けていない場合、HTML は取れることがある。 その場合でも /api/* はヘッダが無いと 401 になるので、レシピ本文と写真は返らない。 本番の閲覧経路はカスタムドメインに Access を付ける前提である。

段 2: アプリ内の身元

worker/util.ts の userEmail が今の人を決める。

条件 結果
Cf-Access-Authenticated-User-Email がある その値を小文字にして使う
Host が localhost または 127.0.0.1 DEV_USER_EMAIL(coptis923@gmail.com)
どちらでもない null → /api/* は 401

/api/* 以外(静的ファイル)はこの判定を通らない。 写真の URL は /api/images?key=... なので、写真も同じ 401 の対象である。 R2 のキーを知っていても、未ログインでは画像を取れない。

ローカルでは Access が無いため、開発者は常に DEV_USER_EMAIL 本人として動く。 別ユーザの見え方を試すには、wrangler.jsonc の DEV_USER_EMAIL を一時的に変えるか、Access の許可メールを増やして本番相当で見る。

共有するもの(世帯の帳面)

Access を通った人は、次を同じように扱える。

対象 できること
コーヒー / 料理のレシピ 一覧、詳細、作成、編集、削除
注湯、材料、手順 編集
写真 追加、並べ替え、削除、URL からの取り込み
編集履歴 誰がいつ保存したかの閲覧

creator_email は「最初に作った人」の記録である。 更新しても作成者は変わらない。 一覧の作成者フィルタは、この列で絞るだけである。他人のレシピを隠す権限ではない。

削除も作成者チェックが無い。 通った人なら、サンプルを含めてどのレシピも消せる。

同時編集は権限ではなく競合である。 保存時に baseUpdatedAt を送り、D1 の updated_at と一致しなければ 409 で弾く。 メッセージは「他の人が先に保存しました」。

ユーザごとに分かれるもの

メールを主キーまたは一部キーにしているものだけが、人を分ける。

対象 キー 他の人から見えるか
プロフィール(表示名、テーマ、アバター) profiles.email 表示名とアバターは編集履歴や作成者の顔として見える。テーマは本人の画面だけ
お気に入り favorites.email 見えない。ホームのお気に入りは今の人の行だけ
編集履歴の「誰が」 recipe_edits.editor_email 見える。共有帳の監査ログ

ホームの「履歴」はサーバに無い。 端末の localStorage なので、同じ Google アカウントでも端末が違えば履歴は共有されない。

操作と範囲

いまの人のメールを email とする。

操作 範囲
GET /api/me、PUT /api/me email のプロフィールだけ
PUT / DELETE /api/favorites/... email の行だけ
GET /api/coffee、GET /api/cooking 全レシピ。creator は任意フィルタ
PUT / DELETE レシピ 全レシピ。作成者で拒否しない
GET /api/edits/... そのレシピの履歴(最大50件)
GET /api/creators 作成者または編集者として出たメールの一覧
POST /api/images 認証済みなら誰でもアップロード。キーは UUID

ロール(管理者 / 閲覧のみ)は無い。 世帯内の「自分のページだけ」も無い。 分けたいデータは、Access の許可メールを増やさないか、別アプリにする。

身元の流れ

flowchart LR
  G[Google アカウント]
  A[Access 許可リスト]
  H["Cf-Access-Authenticated-User-Email"]
  W[Worker userEmail]
  P[profiles / favorites]
  R[共有のレシピ]

  G --> A
  A -->|通ったときだけ| H --> W
  W --> P
  W --> R

Access で弾かれた人は Worker に届かない。 届いた人は、プロフィールだけ自分、レシピは全員、という非対称になる。