「権限管理」は“ユーザーの OK がないと触れない領域をどう扱うか”の話
位置情報・カメラ・マイク・通知・センサー系は、
どれも「ユーザーのプライバシーや安全」に直結します。
だからブラウザは、こういう機能を使うときに
必ず「ユーザーの許可(権限)」を挟みます。
位置情報を取りたい
カメラを使いたい
マイクを使いたい
こういうときに、
「どうやって許可をもらい、どうやって拒否と付き合うか」
を考えるのが「権限管理」です。
ここを雑に扱うと、
「なんか怪しいサイト」「勝手に位置取ってそう」と思われて、
ユーザーに即閉じされます。
逆に、ここを丁寧に設計できると、
「ちゃんとしてるサービスだな」と信頼されます。
ブラウザの権限ダイアログが出るタイミングを理解する
Geolocation API を呼ぶとき、裏で何が起きているか
位置情報を例にします。
navigator.geolocation.getCurrentPosition(success, error);
JavaScriptこのコードが初めて実行されたとき、
ブラウザはこう動きます。
「このサイトは位置情報を使おうとしている」
「ユーザーに許可を聞かないといけない」
→ 画面上部やアドレスバー付近に「位置情報を許可しますか?」ダイアログを表示
ユーザーが「許可」か「ブロック」を選ぶと、
その結果に応じて success か error が呼ばれます。
ここで重要なのは、
許可ダイアログを出すのはブラウザであって、あなたのコードではない
ということです。
あなたができるのは、
いつ Geolocation API を呼ぶか
呼ぶ前にユーザーにどう説明するか
拒否されたときにどう振る舞うか
を設計することです。
権限の状態は「許可・拒否・まだ聞いてない」の 3 つ
Permissions API で状態を覗いてみる
ブラウザは、サイトごとに「権限の状態」を覚えています。
位置情報なら、ざっくり次の 3 パターンです。
許可済み(granted)
拒否済み(denied)
まだ聞いていない(prompt)
これを JavaScript から確認するのが Permissions API です。
async function checkGeoPermission() {
if (!("permissions" in navigator)) {
console.log("Permissions API に対応していません");
return;
}
const status = await navigator.permissions.query({ name: "geolocation" });
console.log("state:", status.state); // "granted" | "denied" | "prompt"
}
checkGeoPermission();
JavaScriptstatus.state に入る値が、今の権限状態です。
granted … すでに許可されている
denied … すでに拒否されている
prompt … まだ聞いていない(初回)
この状態によって、
アプリの振る舞いを変えることができます。
状態ごとにどう振る舞うかを設計する
granted(許可済み)のとき
すでに許可されているなら、
素直に位置情報を取りに行けば OK です。
async function startWithPermissionCheck() {
if (!("permissions" in navigator)) {
// ない場合は、素直に getCurrentPosition を呼ぶしかない
startGeolocation();
return;
}
const status = await navigator.permissions.query({ name: "geolocation" });
if (status.state === "granted") {
// すでに許可済み → すぐに開始
startGeolocation();
} else if (status.state === "prompt") {
// まだ聞いていない → 事前に説明してから開始
showExplainThenStart();
} else if (status.state === "denied") {
// 拒否済み → 設定変更の案内
showHowToEnableMessage();
}
}
JavaScriptここでのポイントは、
「状態によってユーザーへの声かけを変える」 ことです。
prompt(まだ聞いていない)のとき
初回アクセス時など、まだ権限を聞いていない状態です。
このときにいきなり getCurrentPosition を呼ぶと、
ユーザーから見ると
「ページ開いた瞬間に、いきなり位置情報のダイアログが出た」
という体験になります。
これ、結構怖いです。
なので、理想的にはこうします。
画面に「現在地を使って近くのお店を表示します」などの説明を書く
「現在地を使う」ボタンを置く
ボタンが押されたタイミングで getCurrentPosition を呼ぶ
つまり、
「ユーザーの操作 → ブラウザのダイアログ」
という流れにするのが UX 的に自然です。
denied(拒否済み)のとき
一度「ブロック」されたサイトは、
その後 getCurrentPosition を呼んでも、
毎回 PERMISSION_DENIED エラーになります。
コード側から「もう一回聞いて」とは言えません。
権限の再設定は、ユーザーがブラウザの UI から行う必要があります。
だからこそ、アプリ側はこう振る舞うべきです。
「位置情報がブロックされています」
「ブラウザの設定から、このサイトの位置情報を許可してください」
といった案内を出す。
「何度押してもエラーになるボタン」ではなく、
「なぜダメなのか」「どうすれば直るのか」を伝える UI
にすることが大事です。
位置情報の権限管理をコードと UX で組み立てる例
例: 「現在地で近くの店舗を探す」ボタン
HTML:
<button id="useLocationBtn">現在地から店舗を探す</button>
<div id="message"></div>
JavaScript:
const btn = document.querySelector("#useLocationBtn");
const message = document.querySelector("#message");
async function getPermissionState() {
if (!("permissions" in navigator)) return null;
try {
const status = await navigator.permissions.query({ name: "geolocation" });
return status.state; // "granted" | "denied" | "prompt"
} catch {
return null;
}
}
function findShopsWithLocation() {
message.textContent = "現在地を取得中…";
navigator.geolocation.getCurrentPosition(
(position) => {
const c = position.coords;
message.textContent =
`緯度: ${c.latitude}, 経度: ${c.longitude} をもとに店舗を検索します(仮)`;
// ここでサーバーに位置を送って店舗検索などを行う
},
(error) => {
if (error.code === error.PERMISSION_DENIED) {
message.textContent =
"位置情報の利用がブロックされています。ブラウザの設定から、このサイトの位置情報を許可してください。";
} else {
message.textContent = "位置情報を取得できませんでした: " + error.message;
}
},
{
enableHighAccuracy: false,
timeout: 5000,
maximumAge: 60000
}
);
}
btn.addEventListener("click", async () => {
if (!("geolocation" in navigator)) {
message.textContent = "このブラウザは位置情報に対応していません。";
return;
}
const state = await getPermissionState();
if (state === "denied") {
message.textContent =
"位置情報の利用がブロックされています。ブラウザの設定から、このサイトの位置情報を許可してください。";
return;
}
if (state === "prompt") {
message.textContent =
"「許可」を選ぶと、現在地から近くの店舗を探せます。";
}
findShopsWithLocation();
});
JavaScriptこの例でやっていることを整理すると、
権限状態を事前に確認する
denied のときは、無理に API を叩かず、設定変更の案内を出す
prompt のときは、「これからダイアログが出ますよ」と一言説明してから呼ぶ
実際の位置取得は、ユーザーのボタンクリックをトリガーにする
という「コード+UX」の設計になっています。
HTTPS と「安全なコンテキスト」という前提
なぜ HTTP だと権限系 API が動かないのか
位置情報・カメラ・マイク・センサー系の多くは、
「安全なコンテキスト(secure context)」 でしか動きません。
ざっくり言うと、
https:// で配信されているページhttp://localhost(開発用の特例)
のどちらかでないと、navigator.geolocation 自体が使えなかったり、
権限ダイアログが出なかったりします。
理由はシンプルで、
通信が暗号化されていない状態で
位置情報やカメラ映像を扱うのは危険すぎる
からです。
なので、「権限管理」を考えるときは、
「本番は必ず HTTPS」 を前提にしてください。
開発中は http://localhost:3000 などで試し、
本番に上げるときは必ず HTTPS 化する、という流れが基本です。
「権限管理」で本当に大事なのは“人間側の感情”を想像すること
技術的には、
Permissions API で状態を確認できる
getCurrentPosition でダイアログが出る
denied のときは PERMISSION_DENIED になる
といった話で終わりです。
でも、本当に大事なのはその先です。
ユーザーは、
「いきなり位置情報を要求してくるサイト」を怖がります。
「拒否したら何もできないアプリ」にイラッとします。
「なぜ位置が必要なのか説明してくれるサービス」に安心します。
だからこそ、権限管理は
いつ・なぜ・どのように権限を求めるか
拒否されたときに、どうやって代替手段や説明を出すか
権限がなくても、どこまで使えるようにしておくか
まで含めて考える必要があります。
初心者として「権限管理」で掴んでほしいこと
位置情報・センサー系の権限管理の本質は、
「ブラウザのダイアログ任せにせず、ユーザーとのコミュニケーションとして設計する」
ということです。
そのうえで、まずこの感覚を持っておいてください。
権限には「許可・拒否・まだ聞いてない」の 3 状態がある
Permissions API で状態を見て、振る舞いを変えられる
権限を求める前に「なぜ必要か」を UI で説明するのが大事
拒否されたときは、設定変更の案内や代替手段を用意する
コードを書くのは簡単です。
でも、「人にどう見えるか」まで含めて設計できると、
あなたのアプリは一段上の信頼感を持つようになります。
権限管理は、
技術と人間の感情のちょうど境目にあるテーマ です。
ここを丁寧に扱えるエンジニアは、間違いなく強いです。
