JavaScript | Web API:パフォーマンス・セキュリティ - 権限管理設計

JavaScript JavaScript
スポンサーリンク
スポンサーリンク

「権限管理設計」は“技術”じゃなくて“信頼”の設計

位置情報、カメラ、マイク、通知、センサー、ストレージ…。
Web API の多くは「権限(permission)」をユーザーに確認してから使います。

ここで大事なのは、
「どうやって権限を取るか」よりも
「ユーザーにどう信頼してもらうか」 という視点です。

権限設計が雑だと、
「なんか怖いサイト」「よく分からないけど全部聞いてくるサイト」になります。
逆に、丁寧に設計できると、それだけで“ちゃんとしてるサービス”に見えます。


原則 1: 「必要なときに、必要なものだけ」聞く

まとめて全部聞くのは最悪の UX

よくある悪いパターンは、
ページを開いた瞬間に、いきなり権限ダイアログが連発する設計です。

位置情報も
通知も
カメラも
マイクも

「とりあえず全部許可してね」みたいなやつです。

ユーザーからすると、

何に使うのか分からない
今それが必要なのか分からない
とりあえず「拒否」したくなる

という心理になります。

権限設計の基本は、
「その機能を使う直前に、その機能に必要な権限だけを聞く」 ことです。

位置情報が必要になるのは「近くの店を探すボタン」を押したとき
カメラが必要になるのは「写真を撮るボタン」を押したとき
通知が必要になるのは「通知をオンにする設定」をユーザーが選んだとき

このタイミングで初めて、
ブラウザの権限ダイアログを出すようにします。

例: 位置情報を「ボタンを押したときだけ」聞く

HTML:

<p>
  現在地を使って、近くのカフェを表示できます。<br>
  位置情報はサーバーに保存せず、このページ内だけで利用します。
</p>
<button id="nearCafeBtn">近くのカフェを探す</button>
<p id="message"></p>

JavaScript:

const btn = document.querySelector("#nearCafeBtn");
const message = document.querySelector("#message");

btn.addEventListener("click", () => {
  if (!("geolocation" in navigator)) {
    message.textContent = "このブラウザは位置情報に対応していません。";
    return;
  }

  message.textContent = "ブラウザのダイアログで「許可」を選ぶと、近くのカフェを表示できます。";

  navigator.geolocation.getCurrentPosition(
    (pos) => {
      message.textContent = "現在地を取得しました。カフェを検索中…";
      // 検索処理を書く
    },
    (err) => {
      if (err.code === err.PERMISSION_DENIED) {
        message.textContent = "位置情報の利用が拒否されました。手動でエリアを選択できます。";
      } else {
        message.textContent = "位置情報を取得できませんでした。";
      }
    }
  );
});
JavaScript

ここでやっているのは、

ユーザーの操作(ボタン)をきっかけにする
その権限が何に使われるかを事前に説明する
拒否されたときのルートも用意する

という「権限設計の基本形」です。


原則 2: 「用途」と「範囲」を自分の言葉で説明する

ブラウザのダイアログ任せにしない

ブラウザは「位置情報を許可しますか?」と聞いてくれますが、
それだけだとユーザーはこう思います。

何に使うの?
どこまで使われるの?
保存されるの?

だから、アプリ側で先に説明します。

何のために使うのか(例: 近くのカフェを表示するため)
どこまで使うのか(例: このページ内だけで使い、サーバーには保存しない)
いつ使うのか(例: ボタンを押したときだけ)

この 3 つを短く書けると、かなり安心感が出ます。

例: 通知権限を「設定画面」で丁寧に聞く

HTML:

<p>
  お気に入りのカフェのセール情報を通知で受け取ることができます。<br>
  通知は 1 日 1 回までで、いつでもオフにできます。
</p>
<button id="enableNotifyBtn">通知をオンにする</button>
<p id="notifyMessage"></p>

JavaScript:

const btn = document.querySelector("#enableNotifyBtn");
const msg = document.querySelector("#notifyMessage");

btn.addEventListener("click", async () => {
  if (!("Notification" in window)) {
    msg.textContent = "このブラウザは通知に対応していません。";
    return;
  }

  msg.textContent = "ブラウザのダイアログで「許可」を選ぶと、セール情報を通知できます。";

  const result = await Notification.requestPermission();

  if (result === "granted") {
    msg.textContent = "通知が有効になりました。いつでも設定からオフにできます。";
    // 通知登録処理を書く
  } else if (result === "denied") {
    msg.textContent = "通知は拒否されました。後からブラウザの設定で変更できます。";
  } else {
    msg.textContent = "通知の設定は保留されました。";
  }
});
JavaScript

ここで大事なのは、
「ユーザーの不安を先回りして潰す説明」 を入れていることです。

頻度(どれくらいの頻度で通知するか)
取り消し可能性(いつでもオフにできるか)

このあたりを書いておくと、
「一度許可したら終わりではない」と伝わって、心理的ハードルが下がります。


原則 3: 「拒否されても成立する」設計にする

権限は“取れたらラッキー”くらいの気持ちで設計する

権限は、拒否されるのが普通です。
「拒否されたら何もできません」は、設計として弱いです。

位置情報が拒否されたら、エリアを手動選択させる
カメラが拒否されたら、画像アップロードで代替する
通知が拒否されたら、メールやページ内のバッジで知らせる

こういう「代替ルート」を用意しておくと、
権限を取れなくてもサービスとして成立します。

例: 位置情報がなくても検索できる UI

HTML:

<p>
  現在地を使って近くのカフェを探すか、エリアを選択してください。
</p>
<button id="useLocationBtn">現在地で探す</button>

<select id="areaSelect">
  <option value="">エリアを選択</option>
  <option value="shinjuku">新宿</option>
  <option value="shibuya">渋谷</option>
</select>
<button id="searchByAreaBtn">エリアで探す</button>

<p id="result"></p>

JavaScript(位置情報部分だけ抜粋):

useLocationBtn.addEventListener("click", () => {
  if (!("geolocation" in navigator)) {
    result.textContent = "位置情報に対応していません。エリアを選択してください。";
    return;
  }

  navigator.geolocation.getCurrentPosition(
    (pos) => {
      // 現在地で検索
    },
    (err) => {
      if (err.code === err.PERMISSION_DENIED) {
        result.textContent = "位置情報は拒否されました。エリアを選択して検索できます。";
      } else {
        result.textContent = "位置情報を取得できませんでした。エリアを選択してください。";
      }
    }
  );
});
JavaScript

ここでのポイントは、
「拒否されたときのメッセージが“行き止まり”になっていない」 ことです。

「ダメでした」で終わらせず、
「だからこうしてください」と次の行動を提示します。


原則 4: 「権限の状態」をちゃんと把握して、無駄に聞かない

Permissions API で状態を確認する

ブラウザには navigator.permissions という API があり、
一部の権限について「状態」を確認できます。

状態は大きく分けて 3 つです。

granted(許可済み)
denied(拒否済み)
prompt(まだ聞いていない/毎回聞く)

例えば、通知の状態を確認するコードはこうです。

if ("permissions" in navigator) {
  navigator.permissions
    .query({ name: "notifications" })
    .then((status) => {
      console.log("通知の状態:", status.state);
    });
}
JavaScript

これを使うと、

すでに denied なのに、何度もダイアログを出そうとする
すでに granted なのに、毎回「許可してください」と説明する

といった「しつこい・無駄な挙動」を避けられます。

状態に応じて UI を変える

例えば、通知の設定画面でこういう分岐ができます。

granted のとき
「通知はオンです。ブラウザの設定からいつでもオフにできます。」

denied のとき
「通知はブラウザ側で拒否されています。変更するにはブラウザの設定を開いてください。」

prompt のとき
「通知をオンにできます。ボタンを押すとブラウザのダイアログが表示されます。」

これをコードにすると、イメージはこんな感じです。

async function setupNotificationUI() {
  const msg = document.querySelector("#notifyState");

  if (!("Notification" in window)) {
    msg.textContent = "このブラウザは通知に対応していません。";
    return;
  }

  if (!("permissions" in navigator)) {
    msg.textContent = "通知の状態を確認できませんが、ボタンから設定できます。";
    return;
  }

  const status = await navigator.permissions.query({ name: "notifications" });

  if (status.state === "granted") {
    msg.textContent = "通知はオンになっています。ブラウザの設定から変更できます。";
  } else if (status.state === "denied") {
    msg.textContent = "通知はブラウザで拒否されています。設定から変更できます。";
  } else {
    msg.textContent = "通知をオンにできます。ボタンを押すと確認ダイアログが表示されます。";
  }
}
JavaScript

こうやって、
「今どういう状態なのか」をユーザーと共有する のも、権限設計の一部です。


原則 5: 「権限を前提にしない」アーキテクチャにする

権限がなくても“壊れない”コードを書く

権限設計で一番やってはいけないのは、
「権限がないとコードが例外で落ちる」状態です。

例えば、位置情報 API がない環境で
いきなり navigator.geolocation.getCurrentPosition を呼ぶと、
エラーになるブラウザもあります。

なので、必ず存在チェックを挟みます。

if (!("geolocation" in navigator)) {
  // 非対応のときの処理
} else {
  // 対応しているときだけ呼ぶ
}
JavaScript

同じように、
Notification や navigator.permissions も
存在チェックをしてから使うのが基本です。

権限がない
API 自体がない
ユーザーが拒否した

こういう状況を全部「普通のケース」として扱い、
「そのときどう振る舞うか」を先に決めておく のが、権限管理設計です。


初心者として「権限管理設計」で掴んでほしい感覚

権限管理は、API の使い方を覚えることよりも、
ユーザーとの関係性をどう設計するか、という話に近いです。

必要なときに、必要な権限だけを聞く
用途・範囲・頻度を短く説明してからダイアログを出す
拒否されても成立する UI・フローを用意する
Permissions API などで状態を把握し、無駄に聞かない
権限や API を前提にせず、「ない世界」も普通に動くようにする

あなたがコードを書くときに、
「この権限、本当に今必要?」「拒否されたらどうする?」
と一度でも自問できるようになったら、
それはもう“ただ API を叩く人”から
“権限を設計できるエンジニア”に一歩踏み出しています。

タイトルとURLをコピーしました