HTML一枚のSPA上でもブラウザパスワードマネージャに情報を保存したい。
- use-history -- history APIを使った方法
- use-credential-management -- credential management APIを使った方法
https://x.com/i/grok/share/68570649b76a4ad39ae95367a1c730bb
もちろん正攻法はサーバー側にPOSTすること(submitすること)
HTML一枚のSPA上でもブラウザパスワードマネージャに情報を保存したい。
https://x.com/i/grok/share/68570649b76a4ad39ae95367a1c730bb
もちろん正攻法はサーバー側にPOSTすること(submitすること)
| <!DOCTYPE html> | |
| <html lang="ja"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <title>SPA Login with Credential API</title> | |
| </head> | |
| <body> | |
| <form id="login-form"> | |
| <label for="username">ユーザー名:</label> | |
| <input type="text" id="username" name="username" autocomplete="username" required> | |
| <label for="password">パスワード:</label> | |
| <input type="password" id="password" name="password" autocomplete="current-password" required> | |
| <button type="submit">ログイン</button> | |
| </form> | |
| <script> | |
| async function saveCredentials(username, password) { | |
| if ('credentials' in navigator) { | |
| const credential = new PasswordCredential({ | |
| id: username, | |
| password: password, | |
| name: username, // オプション: 表示名 | |
| iconURL: 'https://example.com/icon.png' // オプション: アイコン | |
| }); | |
| try { | |
| await navigator.credentials.store(credential); | |
| console.log('Credential 保存成功'); | |
| } catch (error) { | |
| console.error('保存エラー:', error); | |
| } | |
| } else { | |
| console.log('Credential Management API 非対応'); | |
| } | |
| } | |
| document.getElementById('login-form').addEventListener('submit', function(event) { | |
| event.preventDefault(); | |
| const username = document.getElementById('username').value; | |
| const password = document.getElementById('password').value; | |
| // クライアントサイドのログイン処理(成功したとする) | |
| // 保存呼び出し | |
| saveCredentials(username, password); | |
| alert('ログインしました!'); | |
| }); | |
| </script> | |
| </body> | |
| </html> |
| <!DOCTYPE html> | |
| <html lang="ja"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <title>SPA Login</title> | |
| </head> | |
| <body> | |
| <form id="login-form"> | |
| <label for="username">ユーザー名:</label> | |
| <input type="text" id="username" name="username" autocomplete="username" required> | |
| <label for="password">パスワード:</label> | |
| <input type="password" id="password" name="password" autocomplete="current-password" required> | |
| <button type="submit">ログイン</button> | |
| </form> | |
| <script> | |
| document.getElementById('login-form').addEventListener('submit', function(event) { | |
| event.preventDefault(); // デフォルトのsubmit(POST)を防ぐ | |
| const username = document.getElementById('username').value; | |
| const password = document.getElementById('password').value; | |
| // ここでクライアントサイドのログイン処理(例: ローカルストレージチェックなど) | |
| // 仮に成功したとする | |
| console.log('ログイン成功:', username); | |
| // ブラウザにパスワード保存を促すために、historyを操作 | |
| history.pushState({}, '', location.href); // 同じURLでOK、または'/logged-in'などに変更 | |
| // または新しいパス: history.pushState({}, '', '/app'); | |
| // SPAの続きの処理(例: UI更新) | |
| alert('ログインしました!'); | |
| }); | |
| </script> | |
| </body> | |
| </html> |
chromeはcredential management APIの方しか動かないかも?
python -m http.server 9999 みたいなやつで使う話。