Как стать автором
Обновить

Входите! Аутентификация без логина и пароля, v2

Время на прочтение4 мин
Количество просмотров7.6K
Раз оказалось, что аудитории небезразлична такая тема, как создание одноразовых (работающих в течение некоторого времени) ссылок, позволяющих идентифицировать пользователя.

А особенно в свете того, что я считаю подобное решение (которое я опубликую ниже) приемлемее — решил написать, как решение этой задачи вижу я:

Хранится всё в базе. Mysql только потому, что она сейчас есть под рукой. Для постгре, оракла и sql server решение будет на 99% аналогичным.

Таблица для хранения:

Copy Source | Copy HTML
  1. CREATE TABLE test.one_time_auth(
  2.   token CHAR (32),
  3.   user_id INT (11) UNSIGNED NOT NULL,
  4.   expire DATETIME DEFAULT NULL,
  5.   PRIMARY KEY (token)
  6. )
  7. ENGINE = INNODB


Ну и теперь сам класс + пример работы с ним. В примере мы сначала создаём токен сроком до 31 декабря сего года, а затем его же получаем.

Copy Source | Copy HTML
  1. <?php
  2.  
  3. $db = new PDO('mysql:host=127.0.0.1;dbname=test', 'root');
  4. $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  5.  
  6. $auth = new one_time_auth($db);
  7. $token = $auth->remember(10, '2010-12-31');
  8.  
  9. $user_id = $auth->remind($token);
  10. echo $user_id;
  11.  
  12. class one_time_auth
  13. {
  14.     /**<br/>     * @var PDO<br/>     */
  15.     private $db;
  16.  
  17.     public function __construct(PDO $db)
  18.     {
  19.         $this->db = $db;
  20.     }
  21.  
  22.     public function remember($user_id, $expire = null)
  23.     {
  24.         $sql = 'INSERT INTO one_time_auth (token, user_id, expire) VALUES (:token, :user_id, :expire)';
  25.  
  26.         $stmt = $this->db->prepare($sql);
  27.  
  28.         while (true) {
  29.             try {
  30.                 $stmt->execute(array(
  31.                     ':token' => $token = $this->generateToken(),
  32.                     'user_id' => $user_id,
  33.                     'expire' => $expire
  34.                 ));
  35.                 break;
  36.             } catch (PDOException $e) {}
  37.         }
  38.  
  39.         return $token;
  40.     }
  41.  
  42.     public function remind($token)
  43.     {
  44.         $sql = 'SELECT user_id<br/>                  FROM one_time_auth<br/>                 WHERE token = :token<br/>                  AND (expire IS NULL OR expire <= NOW())<br/>                LIMIT 1';
  45.  
  46.         $stmt = $this->db->prepare($sql);
  47.  
  48.         $stmt->execute(array('token' => $token));
  49.  
  50.         if ($row = $stmt->fetch()) {
  51.             $stmt = $this->db->prepare('DELETE FROM one_time_auth WHERE token = :token');
  52.             $stmt->execute(array('token' => $token));
  53.  
  54.             return $row['user_id'];
  55.         }
  56.     }
  57.  
  58.     private function generateToken()
  59.     {
  60.         return md5(uniqid('', true));
  61.     }
  62. }

PS: код писался «на коленке» просто в качестве ответа на топик habrahabr.ru/blogs/php/109421

PPS: сразу хотелось бы уточнить по поводу md5() — эта функция в данном контексте не добавляет никаких «дыр», это просто способ получить хэш. При желании можно заменить на sha1(), или любой другой по желанию. Главная идея в том, что не нужно завязываться на юзерские данные.
Теги:
Хабы:
Всего голосов 72: ↑54 и ↓18+36
Комментарии17

Публикации

Истории

Работа

PHP программист
148 вакансий

Ближайшие события