- Добавить в БД таблицу пользователей. В таблице должно быть не менее трех полей: id, username, password
- Обновить LoginRequiredMiddeware чтобы он проверял корректность введенных значений по таблице в БД. Доступ к pdo можно получить из функции
apply
через$controller->pdo->prepare(...)
Production / Добавление авторизации
Теперь немного позанимаемся процессом публикации проекта на удалённом сервере так чтобы он был доступен с любого компьютера.
Но прежде озаботимся необходимостью защитить данные от неавторизованного доступа. Сейчас ваше приложение представляет собой что-то среднее между обычным многостраничным сайтом и админкой.
Было бы логично чтобы случайны пользователь не мог редактировать данные.
Для контроля доступа в приложениях принято использовать так называемую концепцию middleware. По сути это специальные обработчики который выполняется либо до непосредственной обработки запроса, либо после.
Ну и собственно главное их назначение — это как раз контроль доступа, всякое логирование, преобразование ответа и т. п. То есть такие штуки которые можно применять сразу к нескольким контролерам.
Давайте создадим базовый Middleware класс в папке framework
вот с таким содержимым
<?php
class BaseMiddleware {
public function apply(BaseController $controller, array $context) {
}
}
теперь идем в Router и сначала правим маршрут:
class Route {
public string $route_regexp;
public $controller;
public array $middlewareList = []; // добавил массив под middleware
// метод с помощью которого будем добавлять обработчик
public function middleware(BaseMiddleware $m) : Route {
array_push($this->middlewareList, $m);
return $this;
}
public function __construct($route_regexp, $controller)
{
// ...
}
}
а теперь подкручиваем сам роутер:
class Router {
// ...
// перепиливаем функцию add таким образом
// добавляем возвращаемый тип : Route
public function add($route_regexp, $controller) : Route {
// создаем экземпляр маршрута
$route = new Route("#^$route_regexp$#", $controller);
array_push($this->routes, $route);
// возвращаем как результат функции
return $route;
}
плюс переопределяем get_or_default
:
class Router {
// ...
public function add($route_regexp, $controller) : Route {
// ...
}
public function get_or_default($default_controller) {
$url = $_SERVER["REQUEST_URI"];
$path = parse_url($url, PHP_URL_PATH);
$controller = $default_controller;
$newRoute = null; // добавили переменную под маршрут
$matches = [];
foreach($this->routes as $route) {
if (preg_match($route->route_regexp, $path, $matches)) {
$controller = $route->controller;
$newRoute = $route; // загоняем соответствующий url маршрут в переменную
break;
}
}
// ...
// вызываем обработчики middleware, если такие есть
if ($newRoute) {
foreach ($newRoute->middlewareList as $m) {
$m->apply($controllerInstance, []);
}
}
return $controllerInstance->process_response();
}
теперь добавим класс обработчик для проверки был ли пользователь авторизован. Для этого создадим папку middlewares и добавим в нее класс
загоним в него просто вывод сообщения, что необходимо авторизоваться
public function apply(BaseController $controller, array $context)
{
echo "Авторизуйтесь пожалуйста";
}
и теперь подключим его во всех контроллерах в которых происходит некоторая манипуляция данными, у меня оказалось четыре таких контроллера:
и теперь попробуем их пооткрывать:
как видно теперь вверху выскакивает надпись. Давайте попробуем реализовать простейшую HTTP авторизацию, она делается с помощью указания специальных заголовков в запросе
class LoginRequiredMiddeware extends BaseMiddleware {
public function apply(BaseController $controller, array $context)
{
// заводим переменные под правильный пароль
$valid_user = "user";
$valid_password = "12345";
// берем значения которые введет пользователь
$user = isset($_SERVER['PHP_AUTH_USER']) ? $_SERVER['PHP_AUTH_USER'] : '';
$password = isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : '';
// сверяем с корректными
if ($valid_user != $user || $valid_password != $password) {
// если не совпали, надо указать такой заголовок
// именно по нему браузер поймет что надо показать окно для ввода юзера/пароля
header('WWW-Authenticate: Basic realm="Space objects"');
http_response_code(401); // ну и статус 401 -- Unauthorized, то есть неавторизован
exit; // прерываем выполнение скрипта
}
}
}
получается такой вполне себе такой колхозный ограничитель неавторизованного доступа.