本人のものだけ
ログインしていれば何でもできる、ではない
前のレッスンで、ログインした人だけが出品できるようになりました。ですがまだ穴があります。
ログインさえしていれば、他人の商品も書き換えられます。 鈴木さんが田中さんの商品を編集したり、消したりできてしまいます。
ここで認可の出番です。「あなたは誰か」は確かめました。次は「それをしてよいか」です。
出品者と突き合わせる
認証ミドルウェアが req.user を用意してくれているので、それと商品の出品者を比べます。
JavaScript
app.put("/items/:id", requireAuth, (req, res) => {
const item = db.prepare("SELECT * FROM items WHERE id = ?").get(Number(req.params.id));
if (!item) {
return res.status(404).json({ error: "商品が見つかりません" });
}
if (item.owner !== req.user.name) {
return res.status(403).json({ error: "この商品は編集できません" });
}
// ここから先は、自分の商品だと分かっている
});第5章の入力検証と同じ構図です。手前で確かめ、奥では信じる。
403 は取り消せない
第7章の最初に書いたとおり、401 と 403 は意味が違います。
401 はログインすれば通ります。403 はログインし直しても通りません。他人の商品は、誰としてログインしても他人の商品だからです。
受け取った側は、この違いで「ログイン画面へ送るのか、それとも諦めてもらうのか」を決められます。
404 と 403 のどちらを先に見るか
上の例では 404 を先に見ています。素直な順番です。
ただし、より慎重な作りでは他人の商品には 404 を返すこともあります。403 を返すと「その id の商品は存在する」と教えることになるからです。
どちらが正しいというより、何を隠したいかで決まります。fleama の商品は誰でも一覧で見られるので、存在を隠す意味はありません。ですから素直に 403 を返します。
認証と認可は場所が違う
| どこに書くか | 理由 | |
|---|---|---|
| 認証 | ミドルウェア | どのルートでも同じ処理 |
| 認可 | 各ルートの中 | 何と突き合わせるかがルートごとに違う |
出品は「ログインしていれば誰でも」、編集は「出品者だけ」、購入は「出品者以外」かもしれません。条件がルートごとに違うので、まとめられません。
手を動かす
演習では、自分の出品だけ編集・削除できるようにします。404 と 403 の順番にも気をつけてください。
要件
PUT /items/:idとDELETE /items/:idの両方にrequireAuthを掛ける- 商品が無ければ 404、出品者が
req.user.nameと違えば 403 を返す - 通れば編集は
{id, name, owner}を 200 で、削除は 204 を本文なしで返す
入出力例
request("PUT", "/items/1", {"name":"革のスニーカー"}, "token-tanaka") → "200 {"id":1,"name":"革のスニーカー","owner":"田中"}"
request("PUT", "/items/2", {"name":"のっとり"}, "token-tanaka") → "403 {"error":"この商品は編集できません"}"
request("PUT", "/items/999", {"name":"x"}, "token-tanaka") → "404 {"error":"商品が見つかりません"}"
request("PUT", "/items/1", {"name":"x"}) → "401 {"error":"ログインしてください"}"
request("DELETE", "/items/1", null, "token-tanaka") → "204 "
request("DELETE", "/items/1", null, "token-suzuki") → "403 {"error":"この商品は編集できません"}"ヒント
編集 ゆめさく編集部