まあ、クッキーにログイン名とパスワードを覚えさせちゃえば終わりだが、「パスワードまでクッキーに保存するのはセキュリティ的に良くない!」っていう感じらしいので、ちょっと工夫してみる。
○前提
A-1. ユーザはIDを持っており、IDからユーザ情報を取得できる。
A-2. セッションを使える。
A-3. クッキーを使える。
A-4. ユーザ情報はデータベースにある。
A-5. PDOを使える。
○方針
B-1. データベースにオートログイン用のテーブルを作成する。
B-2. 通常のログインが成功したとき、ランダムな文字列を生成してクッキーとオートログイン用テーブルに保存する。
B-3. セッションにユーザIDがあるときはログイン中と見なす。ない時はクッキーに保存されたランダムな文字列からオートログイン用テーブルに保存されたユーザIDを取得する。オートログイン用テーブルからユーザIDを取得できた場合は、セッションにユーザIDを残す。
B-4. ユーザIDを取得できればログインできたことにしてユーザ情報をIDから取得する。
○実装
B-1. データベースにオートログイン用のテーブルを作成する。
※SQLiteの例
CREATE TABLE autokeys (
id INTEGER PRIMARY KEY,
cookiekey CHAR(255),
user_id INTEGER,
created DEFAULT NULL,
modified DEFAULT NULL
);
B-2. 通常のログインが成功したとき、ランダムな文字列を生成してクッキーとオートログイン用テーブルに保存する。
define("SHASALT", "marukatuhayatuharisekaiitidatutanodayo"); // eigenvalue for crypt
define("COOKIE_AUTOKEY", "autologinkey"); // cookie name
define("AUTOKEY_TABLE", "autokeys"); // table name of db for autologin
define("USER_KEY", "user_id"); // field name of db to access user's info
define("COOKIE_EXPIRE_AUTOKEY", 60*60*24*10); // time, in which cookie will be deleted.
/**
* オートログイン用にランダムな文字列を発行し、クッキーとオートログイン用テーブルに保存する。
* @param $dbh データベースにアクセスするためのPDOインスタンス
* @param $user_id オートログイン用テーブルに保存する、ユーザID。
* @param $autokeyId nullなら新しくユーザIDとクッキーのセットをデータベースに作成する。nullでないなら更新する。
* @return bool
*/
function set_new_cookiekey(PDO $dbh, $user_id, $autokeyId = null) {
$newkey = sha1((string)$user_id . SHASALT . mt_rand());
$time = time();
if (null === $autokeyId) {
$sql = "INSERT INTO " . AUTOKEY_TABLE . " (cookiekey, " . USER_KEY . ", created, modified) VALUES(?,?,?,?)";
$data = array($newkey, $user_id, $time, $time);
} else {
$sql = "UPDATE " . AUTOKEY_TABLE . " SET cookiekey=?, modified=? WHERE id=?";
$data = array($newkey, $time, $autokeyId);
}
$retval = false;
try {
$stmt = $dbh->prepare($sql);
$retval = $stmt->execute($data);
} catch (PDOException $e) {
// error
}
setcookie(COOKIE_AUTOKEY, $newkey, $time + COOKIE_EXPIRE_AUTOKEY);
return $retval;
}
B-3. セッションにユーザIDがあるときはログイン中と見なす。ない時はクッキーに保存されたランダムな文字列からオートログイン用テーブルに保存されたユーザIDを取得する。オートログイン用テーブルからユーザIDを取得できた場合は、セッションにユーザIDを残す。
define("SESSION_LOGGEDIN", "userid"); // session name
/**
* セッションまたはオートログイン用データベースからユーザIDを取得する。
*
* @param $dbh データベースにアクセスするためのPDOインスタンス
* @return mix ユーザIDまたはfalse
*/
function auto_get_user_id(PDO $dbh) {
session_start();
// If the session info hasn't been set...
if (empty($_SESSION[SESSION_LOGGEDIN])) {
if (!empty($_COOKIE[COOKIE_AUTOKEY])) {
$cookieLogin = false;
$sql = "SELECT * FROM " . AUTOKEY_TABLE . " WHERE cookiekey=?";
try {
$stmt = $dbh->prepare($sql);
if ($stmt->execute(array($_COOKIE[COOKIE_AUTOKEY]))) {
$autokey = $stmt->fetch(PDO::FETCH_ASSOC);
// got entry
if ($autokey && count($autokey) > 0) {
$_SESSION[SESSION_LOGGEDIN] = $autokey[USER_KEY];
// update cookie db
set_new_cookiekey($dbh, $autokey[USER_KEY], $autokey['id']);
$cookieLogin = true;
}
}
} catch (PDOException $e) {
// error
}
if ($cookieLogin) {
// logged in...
return $autokey[USER_KEY];
} else {
// cannot login...
// delete cookie
setcookie(COOKIE_AUTOKEY, "", $time - COOKIE_EXPIRE_AUTOKEY);
return false;
}
} else {
return false;
}
} else {
return $_SESSION[SESSION_LOGGEDIN];
}
}
B-4. ユーザIDを取得できればログインできたことにしてユーザ情報をIDから取得する。
function login($name, $pass) {
$dsn = "sqlite:default.db";
$pdo = new PDO($dsn);
// auto login check
$userid = auto_get_user_id($pdo);
if ($userid) {
// セッションまたはクッキーからログイン
$user= get_user_by_id($userid); // ユーザ情報取得関数
} else {
// フォームからログイン
$user= get_user_by_name_and_pass($name, $pass); // ユーザ情報取得関数
}
return $user;
}
ここまで書いてなんだけど、これはひどい。後から見て全然分からん。
以上
コスミー報告書[社外秘] – [php] オートログイン機能を作る
This savings from ordering Reglaze Glasses Online are usually much quite good when the retailer has fewer overheads and better pricing..
I am continuously invstigating online for ideas that can facilitate me. Thank you!