Авторизация и привилегии

Материал из Wiki

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

Содержание

Постановка задачи

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

Библиотека Auth.php

<?php defined('BASEPATH') or die('No direct script access.');
/*
 * 	Библиотека авторизации включает в себя возможности
 * 	не только автоматической авторизации но и проверку
 * 	прав доступа.
 * 
 * 	Для работы необходимы две таблицы.

	Таблица пользователей
	
		CREATE TABLE users (
  			id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
  			class_id INTEGER UNSIGNED NOT NULL,
  			nick VARCHAR(255) NULL,
  			passw VARCHAR(255) NULL,
  			PRIMARY KEY(id, class_id),
  			INDEX users_FKIndex1(class_id)
		);

	Таблица классов пользователей

		CREATE TABLE class (
  			id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
  			name VARCHAR(255) NULL,
  			description VARCHAR(255) NULL,
  			PRIMARY KEY(id)
		);
*/
class Auth
{
	protected $authorised = false;
	protected $privilegies_table;
	protected $CI = null;
	protected $user;
	protected $config;

	public function __construct()
	{
		//	получаем суперобъект
		$this->CI =& get_instance();
		
		//	массив данных юзера
		$this->user = array(
			'id' => 0,
			'nick' => '',
			'passw' => '',
			'class' => '',
			'class_desc' => '',
			'access' => false
		);
		
		//	устанавливаем дефолтовый конфиг авторизации
		$this->SetAuthConfig();
		//	проверяем авторизацию
		$this->CheckAuth();
		//	загружаем таблицу прав
		$this->CI->load->config('auth_access');
		//	устанавливаем таблицу прав
		$this->SetAccessTable($this->CI->config->item('uaccess'));
	}
	
	//-------------------------------------------------------------------------
	
	/*
	 * 	Возвращаем информацию о пользователе
	 * */
	public function getUser()
	{
		return $this->user;
	}
	
	//-------------------------------------------------------------------------
	
	/*
	 * 	Функция возвращает авторизирован ли юзер
	 * */
	public function isAuthorised()
	{
		return $this->authorised;
	}
	
	//-------------------------------------------------------------------------
	
	/*
	 * 	Проверка на доступ юзера к модулю
	 * */
	public function hasAccess($modulename, $accesstype = '')
	{
		//	если тип доступа юзера к модулю разрешен возвращаем истину
		if($accesstype != '' && isset($modulename))
		{
			if(	isset($this->privilegies_table[$this->user['class']][$modulename])
				&& in_array($accesstype, $this->privilegies_table[$this->user['class']][$modulename]))
			{
				return true;
			}
			else return false;
		}
		//	если доступ юзера к модулю разрешен, возвращаем массив типов доступа
		elseif(isset($modulename))
		{
			if(isset($this->privilegies_table[$this->user['class']][$modulename]))
			{
				$this->user['access'] = $this->privilegies_table[$this->user['class']][$modulename];
				return $this->privilegies_table[$this->user['class']][$modulename];
			}
			else return false;
		}
		else return false;
	}
	
	//-------------------------------------------------------------------------
	
	/*
	 * 	Установка таблицы прав
	 * */
	public function setAccessTable($table)
	{
		if(is_array($table))
		{
			$this->privilegies_table = $table;
		}
	}
	
	//-------------------------------------------------------------------------
	
	/*
	 * 	Функция устанавливает конфиг авторизации.
	 * 
	 * 	Если аргумент не указан то параметры загружается из конфига
	 * 	Структура передаваемого конфига:
	 * 		array(
	 * 			'auth_nick' => <...>,
	 *			'auth_passw' => <...>,
	 *			'auth_form_nick' => <...>,
	 *			'auth_form_passw' => <...>
	 * 		)
	 * */
	public function setAuthConfig($config_array = '')
	{
		if(is_array($config_array))
		{
			$this->config = array(
				'auth_nick' => $config_array['auth_nick'],
				'auth_passw' => $config_array['auth_passw'],
				'auth_form_nick' => $config_array['auth_form_nick'],
				'auth_form_passw' => $config_array['auth_form_passw']
			);
		}
		else
		{
			$this->CI->config->load('auth_config');
			$this->config = array(
				'auth_nick' => $this->CI->config->item('auth_nick'),
				'auth_passw' => $this->CI->config->item('auth_passw'),
				'auth_form_nick' => $this->CI->config->item('auth_form_nick'),
				'auth_form_passw' => $this->CI->config->item('auth_form_passw')
			);
		}
	}
	
	//-------------------------------------------------------------------------

	/*
	 * 		Проверка соответствия данных юзера данным в форме или сессии
	 * */
	public function checkAuth()
	{
		$user = false;
		
		//	строка выборки данных
		/*
		Так было в оригинале:
		$query_string = "SELECT 
							`users`.id,
							`users`.nick,
							`users`.passw,
							`users`.class_id,
							(
								SELECT 
									`class`.name
								FROM
									`class`
								WHERE
									`class`.id = `users`.class_id
							) classname,
							(
								SELECT 
									`class`.description
								FROM
									`class`
								WHERE
									`class`.id = `users`.class_id
							) class_desc
						FROM
							`users`, `class`
						WHERE
							`users`.nick = %s";
		
		Предлагаю заменить на следующее:
		*/
		$query_string = "
			SELECT 
				u.*, c.name AS classname, c.description AS class_desc
			FROM
				".$this->CI->db->dbprefix."users u, ".$this->CI->db->dbprefix."class c
			WHERE
				u.nick = %s AND
				c.id = u.class_id
			LIMIT
				1";

		$this->CI->load->library('session');

		//	если в сессии есть данные
		if	(
				$this->CI->session->userdata($this->CI->config->item('auth_passw'))
				&& $this->CI->session->userdata($this->CI->config->item('auth_nick'))
			)
		{
			//	подготовка данных для запроса
			$nick = $this->CI->session->userdata($this->CI->config->item('auth_nick'));
			$passw = $this->CI->session->userdata($this->CI->config->item('auth_passw'));
		}
		//	или данные отправлены из формы
		elseif	(
					$this->CI->input->post($this->CI->config->item('auth_form_nick')) 
					&& $this->CI->input->post($this->CI->config->item('auth_form_passw'))
				)
		{
			$nick = $this->CI->input->post($this->CI->config->item('auth_form_nick'));
			$passw = $this->CI->input->post($this->CI->config->item('auth_form_passw'));
			$passw = (md5(md5($passw).$this->CI->config->item('encryption_key')));// должно быть вот так, если в базе хранятся md5-хэши паролей! 

                        /* так лучше не делать, так как в этом случае пароль будет храниться в открытом виде 
			$passw = md5($passw.$this->CI->config->item('encryption_key'));//До этого вместо конкатенация стоял знак "+" что приводило к ошибке, т.к. выражение при сложении строк давало 0
*/
		}
		//	иначе авторизация не прошла
		else
		{
			$this->authorised = false;
			return false;
		}
		
		//	выбираем из таблиц информацию
		$this->CI->load->database();
		$query_params = array($this->CI->db->escape($nick));
		$result = $this->CI->db->query(vsprintf($query_string, $query_params));
		$user = $result->row_array();
		
		//	если такой юзер найден
		if($user)
		{
			//	и данные верны
			if	(
					md5($user['passw'].$this->CI->config->item('encryption_key')) == $passw
					&& $user['nick'] == $nick
				)
			{
				//	сохраняем данные в сессии
				$session_data = array(
					$this->CI->config->item('auth_passw') => md5($user['passw'].$this->CI->config->item('encryption_key')),
					$this->CI->config->item('auth_nick') => $user['nick']
				);
				$this->CI->session->set_userdata($session_data);
				
				//	запоминаем данные
				$this->user = array(
					'id' => $user['id'],
					'nick' => $nick,
					'passw' => $passw,
					'class' => $user['classname'],
					'class_desc' => $user['class_desc']
				);
				
				$this->authorised = true;
				return true;
			}
		}
		else
		{
			$this->authorised = false;
			return false;
		}
	}
}
?>

Конфиг авторизации auth_config.php

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

<?php defined('BASEPATH') or die('No direct script access.');
/*
 * 		Конфигурационный файл для библиотеки авторизации 
 * */

//	имя переменной куки, хранящей имя юзера
$config['auth_nick'] = "user";
//	имя переменной куки, хранящей хэш пароля
$config['auth_passw'] = "token";

//	имя поля формы, хранящего имя юзера
$config['auth_form_nick'] = "login";
//	имя поля формы, хранящего пароль юзера
$config['auth_form_passw'] = "password";

//криптоключ
$config['auth_encryption_key'] = "enckey";
?>

Конфиг доступа auth_access.php

Для разграничения прав доступа к какому-либо модулю или разделу существует конфиг доступа

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/*
 * 		Таблица прав доступа
 * 
 *		Возможные значения:
 *
 *		view		-	просмотр
 *		edit		-	редактирование
 *		add			-	добавление
 *		del			-	удаление
 *		opt			-	опционально (возможно при условиях)
 *		view_self,
 *		edit_self,
 *		add_self,
 *		del_self	-	разрешено только со своим
 *		dissalow	-	полный запрет
 *
 *		Эти значения зависят от логики приложения.
 *
 *		Формат конфига:
 *		$config['uaccess'][<имя класса>][<имя модуля>] = array(<перечень разрешений>);
 * */

$config['uaccess']['admin']['adminka'] = array('view');
$config['uaccess']['manager']['adminka'] = array('view');
?>

Простейший хелпер access_helper.php

<?php
/*
 * 		Privilegies helper. Uses Privilegies library
 * 		programmer: Meshin Dmitriy
 * */
function access($modulename, $accesstype = '')
{
	$CI =& get_instance();
	return $CI->auth->hasAccess($modulename, $accesstype);
}
?>

Пример использования

У себя в админке я использую библиотеку в методе контроллера и устанавливаю поле контроллера в истину если юзер авторизован и имеет доступ в админку, иначе в ложь. Метод:

function _check_login()
{
	$this->load->library('auth');
	$this->authorised = $this->auth->isAuthorised() && $this->auth->hasAccess('adminka');
}

Простой пример использования в отображении:

<?php if(access('adminka')):?>
	<div class="marg">[ДОСТУП РАЗРЕШЕН]</div>
<?php endif; ?>

Дополнительный способ использования в конструкторе контроллера (библиотека должна быть уже прописана в файле autoload.php):

function __construct()
  {
     parent::Controller();
     if($this->auth->isAuthorised() == false)
     {
         redirect('login'); //Контроллер авторизации
     }

  }
Личные инструменты