Содержание


Программирование с использованием PHP и MySQL в разработке Web-приложений

Часть 13. Реализация аутентификации средствами mod_auth_mysql

Comments

Серия контента:

Этот контент является частью # из серии # статей: Программирование с использованием PHP и MySQL в разработке Web-приложений

Следите за выходом новых статей этой серии.

Этот контент является частью серии:Программирование с использованием PHP и MySQL в разработке Web-приложений

Следите за выходом новых статей этой серии.

В предыдущих статьях были рассмотрены основные технологии по подготовке СУБД, созданию базового варианта сайта, рассмотрены вопросы, касающиеся создания CMS и методы аутентификации пользователей. В этой статье будет рассмотрена технология использования идентификации пользователей на сайте средствами mod_auth_mysql, которая будут применяться в дальнейших более широких и масштабных проектах.

Использование модуля mod_auth_mysql

Применение модуля mod_auth ограничено на высоконагруженных сайтах с большим количеством пользователей в силу того, что mod_auth хранит регистрационную информацию о пользователях в текстовом файле. В отличие от него, модуль mod_auth_mysql сочетает в себе простоту использования и высокую скорость работы с базой данных (в отличие от работы с текстовыми файлами). Работает mod_auth_mysql похожим образом на mod_auth, но благодаря использованию MySQL способен в разы быстрее производить поиск в больших списках пользователей. Для использования на сервере модуль должен быть скомпилирован и установлен в соответствии с инструкцией по установке.

Установка модуля mod_auth_mysql

Установка модуля mod_auth_mysql подразумевает установленный и настроенный веб-сервер apache и СУБД MySQL. Самые полные инструкции по настройке модуля находятся в файлах README и USAGE дистрибутива, но их описания во многих случаях рассматривают устаревшие версии дистрибутива.

Самая последняя версия для установки доступна на сайте http://sourceforge.net/projects/mod-auth-mysql. После скачивания ее нужно распаковать утилитами zip и tar. Затем надой перейти в каталог mod_auth_mysql и там запустит make и make install, при этом надо при необходимости внести изменения в make файл, касающиеся местонахождения установленной копии MySQL.

Далее необходимо добавить в файл httpd.conf строку, которая позволит обеспечить динамическое использование модуля в сервере apache:

	LoadModule mysql_auth_module libexec/mod_auth_mysql.so

Затем, как правило, в MySQL создается таблица для хранения данных аутентификации. Для этих целей можно использовать уже существующую базу данных и просто создать в ней таблицу, например с именем authorized_users (упоминалась в предыдущих статьях).

Также нужно добавить в файл httpd.conf строку параметров для модуля mod_auth_mysql, которые будут использоваться при подключении к базе данных. Формат этой строки может иметь следующий вид:

	Auth_MySQL_Info имя_хоста имя_пользователя

Самый простой способ проверки работоспособности скомпилированных модулей это проверить запускается ли без ошибок http сервер apache. Для этого можно ввести команду (при наличии поддержки ssl):

/usr/local/apache/bin/apachectl startssl

Если поддержка SSL в apache отсутствует, то команда меняется на:

/usr/local/apache/bin/apachectl start

Если сервер успешно запустится с директивой Auth_MySQL_Info в файле конфигурации httpd.conf, значит, модуль mod_auth_mysql успешно установлен.

Применение модуля mod_auth_mysql

После установки модуля mod_auth_mysql его использование не сложнее, чем рассматриваемого ранее mod_auth. Ниже приведен пример файла .htaccess, позволяющего аутентифицировать пользователей с зашифрованными паролями, которые будут храниться в базе данных.

Код для создания базы данных

create database auth;
use auth;
create table authorised_users ( name varchar(20), 
                                password varchar(40),
                                        primary key     (name)
                              );
insert into authorised_users values ( 'username', 
                                      'password' );

insert into authorised_users values ( 'testuser', 
                                      sha1('password') );
grant select on auth.* 
             to 'webauth' 
             identified by 'webauth';
flush privileges;
	
файл .htaccess

ErrorDocument 401 /rejection.html
AuthName “Realm-Name”
AuthType Basic

Auth_MySQL_DB auth
Auth_MySQL_Encription_Types MySQL
Auth_MySQL_Password_Table authorised_users
Auth_MySQL_UserName_Field name
Auth_MySQL_Password_Field password

require valid-user

Код, расположенный в файле rejection.html

<html><body>
<h1>Немедленно уходите отсюда, или будет вызвана милиция!</h1>
<p>Вам не разрешено здесь находиться.</p>
</body></html>

В файле .htaccess указывается файл с сообщением об ошибке, HTML код которого приведен выше. Снова указывается базовая аутентификация и имя области аутентификации. При этом, доступ разрешен любому пользователю, который успешно прошел аутентификацию.

Применяемый модуль mod_auth_mysql требует своих, особых директив, которые также приведены в файле .htaccess.

Директивы Auth_MySQL, Auth_MySQL_Encription_Types, Auth_MySQL_Password_Table, Auth_MySQL_UserName_Field, Auth_MySQL_Password_Field используются для указания имени базы данных, таблицы и полей имени пользователя и пароля.

Директива Auth_MySQL_Encription_Types обеспечивает выбор типа шифрования. В этом примере выбрано шифрование паролей MySQL. Для отой директивы правильными являются параметры типа Plaintex, Cript_DES, MySQL. Значение Cript_DES применяется по умолчанию и активизирует стандартный для систем типа UNIX алгоритм шифрования пароле DES.

Для пользователя сайта нет никакой разницы, какой тип модуля используется сервером в процессе аутентификации. В любом случае – в браузере отображается диалоговое окно. И если пользователь проходит аутентификацию, то он увидит защищаемое содержимое, в противном случае он увидит сообщение об ошибке.

Модуль mod_auth_mysql подходит практически идеально для большинства сайтов и работает быстро, легко реализуем, и позволяет использовать любые приемлемые механизмы для создания учетных записей пользователей в базе данных. Обеспечение большей гибкости может быть достигнуто при использовании в разработке своих методов аутентификации с применением PHP и MySQL. В любом случае, какой бы метод не был использован, он предполагает полномасштабное использование базы данных, модели доступа к которой определяют способ взаимодействия с СУБД через код PHP. В простейшем случае это определяет то, как и где будет храниться в основном коде SQL-запросы. На сегодняшний день существует четыре основных модели доступа к базам данных – это узкоспециальные запросы, модель активной записи, модель преобразователя и модель интегрированного преобразователя. Рассмотрим все эти модели доступа, как важнейшие компоненты применения СУБД в механизмах аутентификации с использованием mod_auth_mysql.

Узкоспециальные запросы

Узкоспециальные запросы (ad hoc query) – это запросы, которые формируются для решения узкой проблемы в отдельном участке кода. Существует возможность настраивать их на SQL-уровне и делать это гораздо точнее, чем в коде для решения более общих задач. Проблема может заключаться в неконтролируемом росте подобного рода запросов при увеличении задач, которые они должны решать. Для улучшения управляемости ими применяют следующий прием. Все узкоспециальные запросы централизованно размещают в одной библиотеке, призванной решать задачи обработки таких запросов. Более подробно рассмотрим другие, сложные модели.

Модель активной записи

Часто приходится создавать классы, соответствующие записям в базе данных. При этом хорошим решением может стать непосредственная связь доступа к объекту с доступом к поддерживающей его базе данных. Модель активной записи (active record pattern) представляет собой инкапсуляцию в самом классе всех параметров доступа к базе данных для объекта. Ниже рассматривается пример класса user, соответствующий таблице user:

<?php
require_once "DB.inc";

class User {
  public $userid;
  public $username;
  public $firstname;
  public $lastname;
  public $salutation;
  public $countrycode;

  public static function findByUserid($userid)
  {
    return new User($userid);
  }

  public static function findByUsername($username)
  {
  }

  public function __construct($userid = false)
  {
    if(!$userid) {
      return;
    }
    $dbh = new DB_Mysql_Test;
    $query = "SELECT * from users WHERE userid = :1";
    $data = $dbh->prepare($query)->execute($userid)->fetch_assoc();
    foreach( $data as $attr => $value ) {
      $this->$attr = $value;
    }
  }

  public function update()
  {
    if(!$this->userid) {
      throw new Exception("User needs userid to call update()");
    }
    $query = "UPDATE users
              SET username = :1, firstname = :2, lastname = :3, 
                  salutation = :4, countrycode = :5
              WHERE userid = :6";
    $dbh = new DB_Mysql_Test;
    $dbh->prepare($query)->execute($this->username, $this->firstname, 
                                   $this->lastname, $this->salutation,
                                   $this->countrycode, $this->userid);
  }

  public function insert()
  {
    if($this->userid) {
      throw new Exception("User object has a userid, can't insert");
    }
    $query = "INSERT INTO users
                (username, firstname, lastname, salutation, countrycode)
                VALUES(:1, :2, :3, :4, :5)";
    $dbh = new DB_Mysql_Test;
    $dbh->prepare($query)->execute($this->username, $this->firstname, 
                                   $this->lastname, $this->salutation,
                                   $this->countrycode);
    list($this->userid) = 
      $dbh->prepare("select last_insert_id()")->execute()->fetch_row();
  }

  public function delete()
  {
    if(!$this->userid) {
      throw new Exception("User object has no userid");
    }
    $query = "DELETE FROM users WHERE userid = :1";
    $dbh = new DB_Mysql_Test;
    $dbh->prepare($query)->execute($this->userid);
  }
}

$user = User::findByUserid(2);
print_r($user);
$user->countrycode = 'de';
try {
$user->update();
$user2 = User::findByUserid(2);
print_r($user2);
}
catch (Exception $e) {
  print_r($e);
}

?>

Модель преобразователя

В модели преобразователя используется класс, который «знает» как сохранить объект в отдельной схеме базы данных. В примере приведена новая реализация класса user, содержащая сам класс user с логикой приложения и UserMapper – класс, обрабатывающий переменные объекта USER в базу данных и из нее.

<?php

require_once "DB.inc";
class User {
  public $userid;
  public $username;
  public $firstname;
  public $lastname;
  public $salutation;
  public $countrycode;

  public function __construct($userid = false, $username = false,
                              $firstname = false, $lastname = false,
                              $salutation = false, $countrycode = false)
  {
    $this->userid = $userid;
    $this->username = $username;
    $this->firstname = $firstname;
    $this->lastname = $lastname;
    $this->salutation = $salutation;
    $this->countrycode = $countrycode;
  }
}

class UserMapper {
  public static function findByUserid($userid)
  {
    $dbh = new DB_Mysql_Test;
    $query = "SELECT * FROM users WHERE userid = :1";
    $data = $dbh->prepare($query)->execute($userid)->fetch_assoc();
    if(!$data) {
      return false;
    }
    return new User($userid, $data['username'], 
                     $data['firstname'], $data['lastname'], 
                     $data['salutation'], $data['countrycode']);
  }

  public static function insert(User $user)
  {
    if($user->userid) {
      throw new Exception("User object has a userid, can't insert");
    }
    $query = "INSERT INTO users
                (username, firstname, lastname, salutation, countrycode)
                VALUES(:1, :2, :3, :4, :5)";
    $dbh = new DB_Mysql_Test;
    $dbh->prepare($query)->execute($user->username, $user->firstname,
                                   $user->lastname, $user->salutation,
                                   $user->countrycode);
    list($user->userid) =
      $dbh->prepare("select last_insert_id()")->execute()->fetch_row();
  }

  public static function update(User $user)
  {
    if(!$user->userid) {
      throw new Exception("User needs userid to call update()");
    }
    $query = "UPDATE users
              SET username = :1, firstname = :2, lastname = :3,
                  salutation = :4, countrycode = :5
              WHERE userid = :6";
    $dbh = new DB_Mysql_Test;
    $dbh->prepare($query)->execute($user->username, $user->firstname,
                                   $user->lastname, $user->salutation,
                                   $user->countrycode, $user->userid);
  }
  public static function delete(User $user)
  {
    if(!$user->userid) {
      throw new Exception("User object has no userid");
    }
    $query = "DELETE FROM users WHERE userid = :1";
    $dbh = new DB_Mysql_Test;
    $dbh->prepare($query)->execute($userid);
  }
}
?>

Модель интегрированного преобразователя

Данная модель (integrated mapper pattern) является гибридом между моделью моделями преобразователя и активной записи. В примере приводится класс user, реализованный в соответствие с данной моделью.

require_once "DB.inc";
class User {
  public $userid;
  public $username;
  public $firstname;
  public $lastname;
  public $salutation;
  public $countryname;

  public function __construct($userid = false)
  {
    $dbh = new DB_Mysql_Test;
    $query = "SELECT * FROM users u, countries c
              WHERE userid = :1
              AND u.countrycode = c.countrycode";
    $data = $dbh->prepare($query)->execute($userid)->fetch_assoc();
    if(!$data) {
      throw new Exception("userid does nto exist");
    }
    $this->userid = $userid;
    $this->username = $data['username'];
    $this->firstname = $data['firstname'];
    $this->lastname = $data['lastname'];
    $this->salutation = $data['salutation'];
    $this->countryname = $data['name'];
  }

  public static function findByUsername($username)
  {
    $dbh = new DB_Mysql_Test;
    $query = "SELECT userid FROM users u WHERE username = :1";
    list($userid) = 
	$dbh->prepare($query)->execute($username)->fetch_row();
    if(!$userid) {
      throw new Exception("username does nto exist");
    }
    return new User($userid);
  }

  public function insert()
  {
    if($this->userid) {
      throw new Exception("User object has a userid, can't insert");
    }
    $dbh = new DB_Mysql_Test;
    $cc_query = "SELECT countrycode FROM countries WHERE name = :1";
    list($countrycode) = 
      $dbh->prepare($cc_query)->execute
	  ($this->countryname)->fetch_row();
    if(!$countrycode) {
      throw new Exception("Invalid country speicified");
    }
    $query = "INSERT INTO users
                (username, firstname, lastname, salutation, countrycode)
                VALUES(:1, :2, :3, :4, :5)";
    $dbh->prepare($query)->execute($this->username, 
	$this->firstname,
    $this->lastname, $this->salutation, $countrycode, $this->userid);
  }
}
?>

Выводы

В статье на реальных примерах рассмотрены вопросы подготовки и проведения базовой аутентификации средствами PHP и средствами веб-сервера apache. Подробно рассмотрена схема работы mod_auth_mysql, а также реализация его на практике. Приведены примеры и способы реализации представления моделей доступа к базам данных, имеющих большое значение при разработке серьезных проектов.

В следующей статье речь пойдет о восстановлении забытых пользователями сайта паролей.


Ресурсы для скачивания


Похожие темы

  • Программирование с использованием PHP и MySQL в разработке Web-приложений. Часть 1.
  • Программирование с использованием PHP и MySQL в разработке Web-приложений. Часть 2.
  • Программирование с использованием PHP и MySQL в разработке Web-приложений. Часть 3.
  • Программирование с использованием PHP и MySQL в разработке Web-приложений. Часть 4.
  • Программирование с использованием PHP и MySQL в разработке Web-приложений. Часть 5.
  • Программирование с использованием PHP и MySQL в разработке Web-приложений. Часть 6.
  • Программирование с использованием PHP и MySQL в разработке Web-приложений. Часть 7.
  • Программирование с использованием PHP и MySQL в разработке Web-приложений. Часть 8.
  • Программирование с использованием PHP и MySQL в разработке Web-приложений. Часть 9.
  • Программирование с использованием PHP и MySQL в разработке Web-приложений. Часть 10.
  • Программирование с использованием PHP и MySQL в разработке Web-приложений. Часть 11.
  • Программирование с использованием PHP и MySQL в разработке Web-приложений. Часть 12.
  • Программирование с использованием PHP и MySQL в разработке Web-приложений. Часть 13.
  • Программирование с использованием PHP и MySQL в разработке Web-приложений. Часть 14.

Комментарии

Войдите или зарегистрируйтесь для того чтобы оставлять комментарии или подписаться на них.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Linux, Open source
ArticleID=632409
ArticleTitle=Программирование с использованием PHP и MySQL в разработке Web-приложений: Часть 13. Реализация аутентификации средствами mod_auth_mysql
publish-date=03152011