Система авторизации Ion Auth

Материал из Wiki

Перейти к: навигация, поиск

Ссылка на проект — http://github.com/benedmunds/CodeIgniter-Ion-Auth

Документация на английском — http://benedmunds.com/ion_auth/

Ion Auth это простая маленькая система авторизации для CodeIgniter, основанная на Redux Auth 2 (но намного лучше, конечно же). Разработана Беном Эдмундсом (Ben Edmunds), офигенности добавил Фил Стерджен (Phil Sturgeon).

Содержание

Обзор

Структура дистрибутива

|- config
|  '- ion_auth.php
|- controllers
|  '- auth.php
|- language
|  |- english
|     '- ion_auth_lang.php
|  |- russian
|      - ion_auth_lang.php
|  ...
|- libraries
|  '- Ion_auth.php
|- models
|  '- ion_auth_model.php
|- views
|  '- auth
|     |- email
|        |- activate.tpl.php
|        |- forgot_password.tpl.php
|        '- new_password.tpl.php
|     |- change_password.php
|     |- create_user.php
|     |- deactivate_user.php
|     ...
|- ion_auth.sql
|- ion_auth.postgre.sql
|- README.txt

Составляющими самой системы являются каталоги config, language, libraries и models с их содержимым. Каталоги controllers и views содержат контроллеры и отображения для примера использования. В реальном приложении их нужно разрабатывать самостоятельно. Файл ion_auth.sql содержит запрос для создания необходимых таблиц и тестовых данных в MySQL, ion_auth.postgre.sql — соответственно для PostgreSQL.

Установка

Для установки системы скопируйте необходимые каталоги в папку с вашим приложением (обычно — application). Само собой, каталоги config, language и libraries можно скопировать в системный каталог (system) при необходимости.

Настройка

Все настройки находятся в config/ion_auth.php. Рассмотрим их детально. Я буду оформлять текст кусками кода, сопровождая текстовыми комментариями, ибо css для кода в этой вики настроен так, что читать комментарии в самом коде — издевательство над глазами.

/**
	 * Таблицы.
	 **/
	$config['tables']['groups']  = 'groups'; 	
	$config['tables']['users']   = 'users';
	$config['tables']['meta']    = 'meta';
  • groups — таблица, содержащая группы уровней доступа. Например, «модераторы», «администраторы», «простые смертные». Каждого пользователя можно поместить в одну из групп.
  • users — таблица основных данных пользователей (необходимых для авторизации).
  • meta — таблица метаданных пользователей. Обычно это так называемый профиль: имя, фамилия, телефон, адрес и прочее.

Несмотря на кажущееся разделение данных о пользователе, таблица может быть одна. То есть для users и meta можно указать одно и то же имя.

Как вы видите, имена таблиц можно менять, что делает систему весьма гибкой. Например, так:

/**
	 * Таблицы.
	 **/
	$config['tables']['groups']  = 'user_role'; 	
	$config['tables']['users']   = 'user_auth';
	$config['tables']['meta']    = 'user';

После этого нужно поменять соответствующие имена в файле *.sql, с помощью которого вы будете создавать необходимые таблицы.


/**
	 * Название сайта, например, code-igniter.ru
	 */
	$config['site_title']		   = "Сообщество code-igniter.ru";

Заголовок сайта можно использовать в письмах для подтверждения почтового ящика или восстановления пароля. А можно вообще не использовать.


/**
	 * Электропочта администратора, admin@code-igniter.ru
	 */
	$config['admin_email']		   = "admin@code-igniter.ru";

Адрес электронной почты, на который можно высылать различные уведомления или вставлять в письма как адрес техподдержки.


/**
	 * Группа по умолчанию
	 */
	$config['default_group']       = 'members';

Здесь необходимо указать имя группы, к которой будут приписываться все пользователи по умолчанию. Соответственно, такая группа должна существовать в таблице groups.


/**
	 * Группа администраторов по умолчанию
	 */
	$config['admin_group']         = 'admin';

Все пользователи, которых вы решите наделить правами администратора, по умолчанию будут приписываться к этой группе. Аналогично, необходимо создать ее в таблице groups.


/**
	 * Имя столбца в таблице meta, по которому вы хотите соединять ее с таблицей users
	 * Соединение происходит по users.id
	 **/
	$config['join']                = 'user_id';

Раз данные для авторизации и данные профиля хранятся в разных таблицах, то для выборки их необходимо соединять. В этой настройке нужно указать имя столбца в таблице meta, по которому будет происходить соединение в запросе (JOIN) с таблицей users. При текущих настройках (берем значения по умолчанию), эта часть запроса будет выглядеть на SQL так

JOIN users ON users.id=meta.user_id


/**
	 * Столбцы в таблице meta,
	 * id можно не писать.
	 **/
	$config['columns']             = array('first_name', 'last_name', 'company', 'phone');

Перечисляем все столбцы из таблицы метаданных (meta).


/**
	 * Столбец в таблице users, по которому идентифицируем пользователя.
	 **/
	$config['identity']            = 'email';

Имя столбца из таблицы users, по которому происходит идентификация пользователя. Обычно это адрес электронной почты, но может быть, например, именем пользователя (username). Соответственно, записи в этом столбце будут уникальными.


/**
	 * Минимальный размер пароля (в символах)
	 **/
	$config['min_password_length'] = 8;

Минимальное допустимое количество символов в пароле. Хороший пароль не должен быть коротким, но и заставлять пользователя выдумывать слишком длинные пароли тоже не стоит. Это значение затем можно использовать при валидации.


/**
	 * Максимальный размер пароля (в символах)
	 **/
	$config['max_password_length'] = 20;

Максимально возможное количество символов в пароле. Ограничить пароль сверху так или иначе нужно. Опять же, в валидации пригодится.


/**
	 * Активация по электропочте
	 **/
	$config['email_activation']    = false;

Настройка позволяет включить активацию аккаунта по электронной почте. По умолчанию выключено. При включении процесс регистрации будет происходить так:

  • непосредственно регистрация — ввод электропочты, логина (если нужно) и пароля
  • на указанный адрес высылается письмо с кодом активации (прямая ссылка)
  • при переходе по ссылке аккаунт активируется, регистрация завершается

Если пользователь указал неверный или чужой адрес, письмо он, само собой, не получит, а значит и аккаунт будет недоступен.


/**
	 * Нужно ли разрешить запоминание логина и возможность автовхода
	 **/
	$config['remember_users']      = true;

В форме логина вы можете предоставить пользователю чекбокс а-ля «запомнить». Когда пользователь входит с отмеченным чекбоксом, система запомнит его и при следующем входе на сайт автоматически авторизует.

Эта настройка разрешает или запрещает такую функцию. По умолчанию включена.


/**
	 * Как долго помнить пользователя (в секундах)
	 **/
	$config['user_expire']         = 86500;

Можно установить время (в секундах), в течение которого система будет помнить пользователя (время жизни куки, другими словами).


/**
	 * Продлевать жизнь куке при каждом автовходе пользователя
	 **/
	$config['user_extend_on_login'] = false;

Если ничего не делать, то независимо от включенного автовхода однажды пользователь не сможет войти, даже если посещал сайт каждые 10 минут. Эта настройка позволяет продлить жизнь авторизации при каждом автовходе пользователя.

Допустим, пользователь авторизовался, и система запомнила его на 24 часа. По истечении 23 часов 59 минут он снова заходит на сайт, и система снова дает ему 24 часа, в течение которых он может зайти без ввода логина и пароля.


/**
	 * Каталог, в котором хранятся шаблоны писем.
	 **/
	$config['email_templates']     = 'auth/email/';

Путь к каталогу, в котором будут храниться шаблоны писем для активации пользователя и восстановления пароля. Путь прописывается относительно каталога views.


/**
	 * Имя шаблона письма для активации пользователя
	 **/
	$config['email_activate']   = 'activate.tpl.php';

Имя шаблона письма, высылающегося при активации пользователя.


/**
	 * Имя шаблона письма для восстановления пароля
	 **/
	$config['email_forgot_password']   = 'forgot_password.tpl.php';

Имя шаблона письма, высылающегося в ответ на запрос «забыл пароль».


/**
	 * Имя шаблона письма при завершении процедуры восстановления пароля
	 **/
	$config['email_forgot_password_complete']   = 'new_password.tpl.php';

Имя шаблона письма, высылающегося по окончанию процедуры восстановления пароля.


/**
	 * Длина «соли»
	 **/
	$config['salt_length'] = 10;

Пароли в базе хранятся в виде хэша. Для усиления функции хэширования используется дополнительный ключ («соль»). Здесь указывается его длина (в символах).


/**
	 * Должна ли «соль» храниться в базе данных?
	 * Это изменит алгоритм кодирования вашего пароля, 
	 * пароль по умолчанию (password) необходимо будет изменить на 
	 * fbaa5e216d163a02ae630ab1a43372635dd374c0 с «солью» по умолчанию.
	 **/
	$config['store_salt'] = false;

От этой настройки зависит метод хэширования пароля. Используется алгоримт SHA1.

Если установлено FALSE (по умолчанию), то хэш будет сгенерирован так:

  • генерация «соли» случайным образом
  • получение хэша от конкатенации соли и пароля
  • конкатенация соли и полученного хэша, обрезанного сзади на длину соли

При TRUE хэш будет генерироваться сразу из конкатенации пароля и «соли».


/**
	 * Префикс стандартного сообщения
	 **/
	$config['message_start_delimiter'] = '<p>';

При желании можно указать начало каждого сообщения от системы. Это может быть любой текст, но чаще всего это тег или несколько тегов. Если вы собираетесь сами форматировать сообщения, значение можно оставить пустым.


/**
	 * Постфикс стандартного сообщения
	 **/
	$config['message_end_delimiter'] = '</p>';

Текст, завершающий стандартное сообщение.


/**
	 * Префикс сообщения об ошибке
	 **/
	$config['error_start_delimiter'] = '<p>';
/**
	 * Постфикс сообщения об ошибке
	 **/
	$config['error_end_delimiter'] = '</p>';

Аналогично для сообщений об ошибках.

Применение

Здесь я остановлюсь лишь на ключевых моментах, так как применение библиотеки можно изучить по примеру контроллера auth, находящегося в каталоге controllers дистрибутива.

Для работы библиотеки Ion Auth необходимо подключить библиотеки сессий и базы данных. Можно сделать это в конструкторе контроллера.

function __construct() 
    {
        parent::__construct();
		
		$this->load->library('ion_auth');
		$this->load->library('session');
		$this->load->database();
    }

Регистрация

Итак, у нас есть форма регистрации с несколькими полями.

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

if ( $this->ion_auth->logged_in() ) 
	{
		redirect('', 'refresh');
	}

Метод logged_in возвращает TRUE или FALSE в зависимости от того, авторизован пользователь или нет. Вместо редиректа можно сделать что-то другое.

Если форма регистрации находится в админке, то эта страница должна быть доступна только администраторам.

if ( ! $this->ion_auth->logged_in() OR ! $this->ion_auth->is_admin() ) 
	{
		redirect('auth', 'refresh');
	}

Проверяем, авторизован ли пользователь и включен ли в группу администраторов (функция is_admin).

Далее считаем, что пользователь регистрируется самостоятельно, заполняя регистрационную форму.

В указанную нами функцию приходят POST-данные со страницы регистрации. Здесь по желанию можно устроить валидацию, но я не буду на ней останавливаться.

В случае, если валидация прошла успешно, делаем так

$username  = strtolower($this->input->post('first_name')).' '.strtolower($this->input->post('last_name'));
	$email     = $this->input->post('email');
	$password  = $this->input->post('password');
	
	$additional_data = array('first_name' => $this->input->post('first_name'),
							'last_name'  => $this->input->post('last_name'),
					'company'    => $this->input->post('company'),
					'phone'      => $this->input->post('phone1') .'-'. $this->input->post('phone2') .'-'. $this->input->post('phone3'),
					   );
	
	if ( $this->ion_auth->register($username, $password, $email, $additional_data) ) 
	{
		$this->session->set_flashdata('message', "Вы зарегистрированы!");
		redirect("auth", 'refresh');
	} 
	else 
	{ 
		$this->data['message'] = (validation_errors()) ? ($this->ion_auth->errors() ? $this->ion_auth->errors() : validation_errors()) : $this->session->flashdata('message');
		//...
	}

Метод register производит регистрацию пользователя. У метода 5 параметров, из которых лишь последний необязательный:

  • username — имя пользователя
  • password — пароль
  • email — адрес электронной почты
  • additional_data — метаданные (массив)
  • group_name — имя группы, к которой необходимо приписать пользователя

Таким образом, при помощи библиотеки input мы получаем данные, обрабатываем их так, как нам хочется, формируем нужные поля и передаем в функцию register. Функция вернет TRUE в случае успешной регистрации, и FALSE в случае ошибки (например, пользователь с таким email/username уже зарегистрирован). Далее мы можем сообщить пользователю, что он успешно зарегистрирован или, в случае неудачи, вернуть его на страницу регистрации и показать те ошибки, которые он допустил, или причину, по которой он не может зарегистрироваться.

Сообщения от системы возвращает функция messages, а ошибки функция errors.

Активация аккаунта

Если соответствующая настройка включена, пользователю будет выслано письмо со ссылкой для активации. Простейший шаблон такого письма выглядит так

<!doctype html>
	<html>
	<body>
		<h1>Активация аккаунта «<?php echo $identity;?>»</h1>
		<p>Пожалуйста, кликните по ссылке, чтобы <?php echo anchor('auth/activate/'. $id .'/'. $activation, 'активировать аккаунт');?>.</p>
	</body>
	</html>

Как видно, при загрузке этого шаблона необходимо передать параметры 'identity' — идентификатор (email по умолчанию, как мы помним), 'id' (собственно id пользователя из таблицы users) и 'activation' (код активации).

В данном случае url выглядит так: /auth/activate/[id]/[code], но вы можете сделать его таким, каким хочется.

Пользователь получает письмо и переходит по ссылке. Функция activate контроллера auth получает данные.

function activate($id, $code=false) 
	{        
		$activation = $this->ion_auth->activate($id, $code);
		
        if ($activation) {
	        $this->session->set_flashdata('message', $this->ion_auth->messages());
	        redirect("auth", 'refresh');
        }
        else 
		{
	        $this->session->set_flashdata('message', $this->ion_auth->errors());
	        redirect("auth/forgot_password", 'refresh');
        }
    }

Активация происходит при помощи функции activate библиотеки, в которую передаются 2 параметра:

  • id — id пользователя из таблицы users
  • code — код активации (получается как хэш от времени)

Авторизация

Теперь пользователь счастлив, ибо его аккаунт активен. Что происходит при попытке войти на сайт. Опять же код привожу без учета валидации, считаем, что все введено корректно.

if ($this->ion_auth->login($this->input->post('email'), $this->input->post('password'), $remember)) 
	{ 
		$this->session->set_flashdata('message', $this->ion_auth->messages());
		redirect($this->config->item('base_url'), 'refresh');
	}
	else 
	{
		$this->session->set_flashdata('message', $this->ion_auth->errors());
		redirect('auth/login', 'refresh');
	}

Функция, авторизующая пользователя, — login. У функции 3 параметра:

  • identity — идентификатор пользователя (в данном случае — email, указывается в настройках, как мы помним)
  • password — пароль
  • remember — (необязательный) запоминать ли пользователя для автовхода

Функция возвращает TRUE в случае успеха (при этом messages возвращает сообщение о входе) и FALSE в случае неудачи (а при этом errors выдает список ошибок).

Если пользователь успешно авторизован, его можно перенаправить на нужную (например, главную) страницу редиректом. В случае ошибки можно тем же редиректом вернуть его на страницу входа с указанием ошибок.

Выход

Тут все просто (хотя и в других местах не сложно) — функция logout. Никаких параметров, вызов убивает текущий сеанс.

$this->ion_auth->logout();

Список функций библиотеки

Ниже я просто перечислю все функции этой библиотеки с описанием параметров и сообщениями, которые при этом возращаются функциями messages и errors.

  • activate($id, $code=false) — активация аккаунта
    $id — id из таблицы users
    $code — код активации
    messages: activate_successful
    errors: activate_unsuccessful
  • deactivate($id) — деактивация аккаунта
    $id — id из таблицы users
    messages: deactivate_successful
    errors: deactivate_unsuccessful
  • change_password($identity, $old, $new) — сменить пароль
    $identity — идентификатор пользователя
    $old — старый пароль
    $new — новый пароль
    messages: password_change_successful
    errors: password_change_unsuccessful
  • forgotten_password($email) — выслать письмо для восстановления пароля
    $email — адрес электропочты, на который нужно выслать письмо
    messages: forgot_password_successful
    errors: forgot_password_unsuccessful
  • forgotten_password_complete($code) — проверить код для завершения восстановления пароля
    $code — код из письма для восстановления пароля
    messages: password_change_successful
    errors: password_change_unsuccessful
  • register($username, $password, $email, $additional_data, $group_name = false) — создать нового пользователя
    $username — имя пользователя
    $password — его пароль
    $email — адрес электронной почты
    $additional_data — метаданные
    $group_name — имя группы, к которой нужно причислить пользователя
    messages: account_creation_successful, activation_email_successful
    errors: account_creation_unsuccessful, deactivate_unsuccessful, activation_email_unsuccessful
  • login($identity, $password, $remember=false) — авторизовать пользователя
    $identity — идентификатор пользователя
    $password — его пароль
    $remember — запоминать ли пользователя для автовхода
    messages: login_successful
    errors: login_unsuccessful
  • logout() — завершить текущий сеанс, выйти
    messages: logout_successful
  • logged_in() — проверить, авторизован ли пользователь
  • is_admin() — проверить, является ли пользователь администратором
  • is_group($check_group) — проверить, является ли пользователь членом указанной группы
    $check_group — группа, принадлежность к которой нужно проверить
  • profile() — возвращает объект, содержащий данные профиля (все поля) текущего пользователя
  • get_users($group_name = false) — получить список всех пользователей указанной группы, либо вообще всех, если группа не указана; возвращает объект
    $group_name — группа, список пользователей которой нужно получить
  • get_users_array($group_name = false) — получить список всех пользователей указанной группы, либо вообще всех, если группа не указана; возвращает массив
    $group_name — группа, список пользователей которой нужно получить
  • get_newest_users($limit = 10) — получить список нескольких последних пользователей; возвращает объект
    $limit — количество пользователей, которое нужно получить
  • get_newest_users_array($limit = 10) — получить список нескольких последних пользователей; возвращает массив
    $limit — количество пользователей, которое нужно получить
  • get_active_users($group_name = false) — получить список всех активных пользователей указанной группы, либо вообще всех активных пользователей, если группа не указана; возвращает объект
    $group_name — группа, список пользователей которой нужно получить
  • get_active_users_array($group_name = false) — получить список всех активных пользователей указанной группы, либо вообще всех активных пользователей, если группа не указана; возвращает массив
    $group_name — группа, список пользователей которой нужно получить
  • get_inactive_users($group_name = false) — получить список всех НЕактивных пользователей указанной группы, либо вообще всех НЕактивных пользователей, если группа не указана; возвращает объект
    $group_name — группа, список пользователей которой нужно получить
  • get_inactive_users_array($group_name = false) — получить список всех НЕактивных пользователей указанной группы, либо вообще всех НЕактивных пользователей, если группа не указана; возвращает массив
    $group_name — группа, список пользователей которой нужно получить
  • get_user($id=false) — получить профиль указанного пользователя, либо текущего, если id не указан; возвращает объект
    $id — id пользователя, профиль которого нужно получить
  • get_user_by_email($email) — аналогично get_user, только в качестве параметра — адрес электропочты
    $email — адрес электронной почты, по которому нужно найти пользователя
  • get_user_array($id=false) — получить профиль указанного пользователя, либо текущего, если id не указан; возвращает массив
    $id — id пользователя, профиль которого нужно получить
  • update_user($id, $data) — обновить данные указанного пользователя
    $id — id пользователя
    $data — ассоциативный массив данных
  • delete_user($id) — удалить указанного пользователя
    $id — id пользователя
  • extra_where() — функция для добавления дополнительных полей профиля в запросы
    неограниченное число аргументов
  • extra_set() — функция для установки дополнительного поля регистрации
    неограниченное число аргументов
  • set_message_delimiters($start_delimiter, $end_delimiter) — установить префикс и постфикс для стандартных сообщений
    $start_delimiter — префикс
    $end_delimiter — постфикс
  • set_error_delimiters($start_delimiter, $end_delimiter) — установить префикс и постфикс для сообщений об ошибках
    $start_delimiter — префикс
    $end_delimiter — постфикс
  • set_message($message) — установить стандартное сообщение
    $message — текст сообщения
  • set_error($message) — установить сообщение об ошибке
    $message — текст сообщения
  • messages() — возвращает стандартные сообщения от системы
  • errors() — возвращает сообщения об ошибках от системы
Личные инструменты