Запоминаем пользователя в cookie

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

Обычно куки устанавливаются на какой-то определенный срок (например, на месяц) или навсегда. Во втором случае пользователь будет авторизован (то есть сможет входить на сайт без ввода пароля) пока не перейдет по ссылке 'Выйти' или не зайдет с другого браузера (в нем-то куку мы не устанавливали!).

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

При заходе на сайт мы первым делом проверяем не запущена ли сессия. Если запущена - значит пользователь авторизован.

Если не запущена, тогда мы смотрим ему в куки и ищем там пометку об авторизации.

Пометка должна выглядеть так: в одной куке мы пишем логин, а во второй - случайную строку (аналог пароля).

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

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

Если не совпадает - показываем ему форму авторизации.

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

Делать это стоит только в том случае, если пользователь поставил галочку 'запомнить меня'.

Почему? Потому что пользователь может находится не за своим компьютером и поэтому не хочет, чтобы другой человек после него смог авторизоваться под его логином по кукам (то есть не вводя пароля!).

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

Реализуем работу с куками

Итак, приступим к реализации. Первым делом добавим в таблицу users новое поле cookie:

id login (Логин) password (Соленый пароль) salt (Соль) cookie (Куки)
1 user 827ccb0eea8a706c4c34a16891f84e7b sdfLjgyl
2 admin 01cfcd4f6b8770febfb40cb906715822 sMtrnwpJ

Для генерации кук мы будем пользоваться функцией generateSalt, которая уже упоминалась раньше при генерации соли.

Модифицируем форму авторизации так, чтобы пользователю была видна галочка (checkbox) 'Запомнить меня'.

Если он отмечает эту галочку при авторизации - будем запоминать его в куки, если не отмечает - не будем:

<!-- Это форма авторизации: -->
	<form action='index.php' method='POST'>
		<input name='login'>
		<input name='password' type='password'>
		<input name='remember' type='checkbox' value='1'>
		<input type='submit' value='Отправить'>
	</form>
<!-- Конец формы авторизации. -->

Код для авторизации по логину и паролю (полный код можете посмотреть в том уроке, где мы солили пароль, здесь только часть, которая подвергнется изменению):

Файл auth.php

<?php
	...

	//Если соленый пароль из базы совпадает с соленым паролем из формы...
	if ($user['password'] == $saltedPassword) {
		//Стартуем сессию:
		session_start(); 

		//Пишем в сессию информацию о том, что мы авторизовались:
		$_SESSION['auth'] = true;

		/*
			Пишем в сессию логин и id пользователя
			(их мы берем из переменной $user!):
		*/
		$_SESSION['id'] = $user['id']; 
		$_SESSION['login'] = $user['login']; 

		//Проверяем, что была нажата галочка 'Запомнить меня':
		if ( !empty($_REQUEST['remember']) and $_REQUEST['remember'] == 1 ) {
			//Сформируем случайную строку для куки (используем функцию generateSalt):
			$key = generateSalt(); //назовем ее $key

			//Пишем куки (имя куки, значение, время жизни - сейчас+месяц)
			setcookie('login', $user['login'], time()+60*60*24*30); //логин
			setcookie('key', $key, time()+60*60*24*30); //случайная строка

			/*
				Пишем эту же куку в базу данных для данного юзера.

				Формируем и отсылаем SQL запрос:
				ОБНОВИТЬ  таблицу_users УСТАНОВИТЬ cookie = $key ГДЕ login=$login.
			*/
			$query = 'UPDATE users SET cookie="'.$key.'" WHERE login="'.$login.'"';
			mysqli_query($link, $query);
		}
	}
	...
?>

Теперь напишем код для авторизации по кукам.

Этот код должен выполняться при каждом заходе пользователя на сайт.

<?php
	/*
		Если пользователь не авторизован (проверяем по сессии) -
		тогда проверим его куки, если в куках есть логин и ключ,
		то пробьем их по базе данных.
		Если пара логин-ключ подходит - пишем авторизуем пользователя.

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

		Если пустая переменная auth из сессии ИЛИ она равна false (для авторизованного она true).
	*/
	if (empty($_SESSION['auth']) or $_SESSION['auth'] == false) {
		//Проверяем, не пустые ли нужные нам куки...
		if ( !empty($_COOKIE['login']) and !empty($_COOKIE['key']) ) {
			//Пишем логин и ключ из КУК в переменные (для удобства работы):
			$login = $_COOKIE['login']; 
			$key = $_COOKIE['key']; //ключ из кук (аналог пароля, в базе поле cookie)

			/*
				Формируем и отсылаем SQL запрос:
				ВЫБРАТЬ ИЗ таблицы_users ГДЕ поле_логин = $login.
			*/
			$query = 'SELECT*FROM users WHERE login="'.$login.'" AND cookie="'.$key.'"';

			//Ответ базы запишем в переменную $result:
			$result = mysqli_fetch_assoc(mysqli_query($link, $query)); 

			//Если база данных вернула не пустой ответ - значит пара логин-ключ_к_кукам подошла...
			if (!empty($result)) {
				//Стартуем сессию:
				session_start(); 

				//Пишем в сессию информацию о том, что мы авторизовались:
				$_SESSION['auth'] = true; 

				/*
					Пишем в сессию логин и id пользователя
					(их мы берем из переменной $user!):
				*/
				$_SESSION['id'] = $user['id']; 
				$_SESSION['login'] = $user['login']; 

				//Тут можно добавить перезапись куки, см. ниже объяснение.
			}
		}
	}
?>

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

С одной стороны это хорошо, а с другой - плохо. Лучше будет, если пользователь не сможет зайти по кукам и ему придется вводить пароль.

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

Добавьте этот код самостоятельно (он есть в предпоследнем примере).

Куки и безопасность

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

Это может быть удаление аккаунта, редактирование какой-либо важной информации, изменение пароля и другое.

Логаут

Дадим пользователю возможность нажать на кнопку 'Выйти' и перестать быть авторизованным.

Если раньше нам нужно было удалить только сессию, то теперь следует удалить также и куки:

Код для файла logout.php

<?php
	//Если переменная auth из сессии не пуста и равна true, то...
	if (!empty($_SESSION['auth']) and $_SESSION['auth']) {
		session_start();
		session_destroy(); //разрушаем сессию для пользователя

		//Удаляем куки авторизации путем установления времени их жизни на текущий момент:
		setcookie('login', '', time()); //удаляем логин
		setcookie('key', '', time()); //удаляем ключ
	}
?>