[php] オートログイン機能を作る

まあ、クッキーにログイン名とパスワードを覚えさせちゃえば終わりだが、「パスワードまでクッキーに保存するのはセキュリティ的に良くない!」っていう感じらしいので、ちょっと工夫してみる。

○前提
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 パーマリンク

[php] オートログイン機能を作る への3件のフィードバック

  1. 安倍なつみ ビキニ のコメント:

    コスミー報告書[社外秘] – [php] オートログイン機能を作る

  2. imitation oakley のコメント:

    This savings from ordering Reglaze Glasses Online are usually much quite good when the retailer has fewer overheads and better pricing..

  3. BVUXRBTYLFEFUUD のコメント:

    I am continuously invstigating online for ideas that can facilitate me. Thank you!

コメントを残す

メールアドレスが公開されることはありません。