ユーザー操作制御機能(何)を作ってみる
前置き
最近、自分でコーディングする機会がめっきり減ってしまったので、ちょっとしたリハビリにちょっとしたものを作ってみる。
いい名前が思いつかなかったので、こんなタイトル(何)になってしまったが、要するに、
によって、ある操作を行いたいときには追加で認証を求めるという仕組み。
- 普段は使わない/誤操作が怖い「編集」や「削除」ボタンなどを、普段は無効にしておくことで誤操作を防ぐ
- 離席中に誰かが操作しようとしても、認証を求められるから安心
みたいな効果が期待されるのは、きっと周知の事実(謎)。
ざっくりとした構成
適当に設計してみる。
サーバー側の処理
まずは、機能ロック状態マネージャ。(ファイル名:UnlockManager.php)
<?php class UnlockManager { const UNLOCKED_SPAN = 300; // 5 minutes public static function setUnlocked($funcName) { self::sessionStart(); $_SESSION['unlock'][$funcName] = array( "lastUnlocked" => time(), ); } public static function isUnlocked($funcName) { self::sessionStart(); if (isset($_SESSION['unlock'][$funcName]['lastUnlocked'])) { if ($_SESSION['unlock'][$funcName]['lastUnlocked'] + self::UNLOCKED_SPAN < time()) { unset($_SESSION['unlock'][$funcName]); } return isset($_SESSION['unlock'][$funcName]['lastUnlocked']); } else { return false; } } public static function getLastUnlocked($funcName) { self::sessionStart(); if (isset($_SESSION['unlock'][$funcName]['lastUnlocked'])) { return $_SESSION['unlock'][$funcName]['lastUnlocked']; } else { return false; } } private static function sessionStart() { $sid = session_id(); if (empty($sid)) { session_start(); } } }
次は、ロック解除API。(ファイル名:unlock.php)
<?php require_once('UnlockManager.php'); if (isset($_POST['userId'], $_POST['password'], $_POST['func'])) { $userId = $_POST['userId']; $password = $_POST['password']; $func = $_POST['func']; // TODO 実際は、ちゃんとユーザー認証 if ($userId == "admin" && $password == "admin") { UnlockManager::setUnlocked($func); } $res = array('unlocked' => UnlockManager::isUnlocked($func)); } else if (isset($_POST['func'])) { $func = $_POST['func']; $res = array('unlocked' => UnlockManager::isUnlocked($func)); } else { $res = array('unlocked' => false); } print(json_encode($res));
クライアント側の処理
処理を簡単に書くために、prototype.js(v1.7.0)を使用。
PHP用のテンプレートエンジンとかを使えばもうちょっときれいに書けただろうけど、とりあえずはPHPファイルの中にHTMLをべたっと。(ファイル名:app.php)
<?php require_once('UnlockManager.php'); ?> <html> <head> <title>Unlock test</title> <script type="text/javascript" src="prototype.js"></script> <script type="text/javascript"> <!-- function init() { Ajax.Responders.register({ onComplete: function(req) { var res = eval("(" + req.transport.responseText + ")"); if (res.unlocked) { window.location.reload(); } } }); } function auth(func) { $('form1').func.value = func; $('unlock').style.display = ''; return false; } function setUnlocked() { $('unlock').style.display = 'none'; new Ajax.Request('unlock.php', { parameters: $('form1').serialize(true) }); return false; } //--> </script> </head> <body onload="init()"> <div style="display:none" id="unlock"> <form action="" method="post" name="form1" id="form1"> <input type="text" name="userId" autocomplete="off" /><br /> <input type="password" name="password" autocomplete="off" /><br /> <input type="hidden" name="func" /> <input type="button" value="OK" onclick="setUnlocked();" /> </form> </div> <table> <?php foreach (array('func_1', 'func_2', 'func_3') as $func) { ?> <tr> <th><?php print($func);?></th> <td> <?php if (UnlockManager::isUnlocked($func)) { ?> <input type="button" value="Do <?php print($func);?>" /> <?php } else { ?> <input type="button" value="Do <?php print($func);?>" disabled="true" /> <?php } ?> </td> <td> <?php if (UnlockManager::isUnlocked($func)) { ?> [ ] <?php } else { ?> <a href="#" onclick="auth('<?php print($func);?>');">][</a> <?php } ?> </td> </tr> <?php } ?> </table> <hr /> <h2>debug output</h2> <pre> <?php print_r(array("time" => time(), "session" => $_SESSION['unlock'])); ?> </pre> </body> </html>
蛇足
app.php にアクセスし、"]["(扉が閉じている図のつもり)をクリックすると、認証用のフォームが表示される。
正しいユーザーID/パスワードを入力してOKをクリックすると、選択した機能のボタン("Do func_x")が押せるようになる。
5分以上経過した後にページをリロードすると、再び機能のボタンが押せなくなる。
管理者はいろんなことができちゃって怖いので、普段はこういう機能によって操作を制限されていると安心かもね。