Как сделать логин пароль html
Форма входа и регистрации с помощью HTML5 и CSS3
Здесь мы использовали несколько приемов HTML5. Например, элемент type=password автоматически скрывает то, что пользователь печатает и заменяет символы точками или звездочками (зависит от браузера). Элемент type=email позволяет браузеру проверить правильность формата email адреса. Кроме того, мы использовали параметр require=required; браузеры, поддерживающие данный параметр не позволят пользователю отправить форму до тех пор, пока поле не заполнено, JavaScript здесь не требуется. Параметр autocomplete=on будет автоматически заполнять некоторые поля. Мы также использовали замещающийся текст, который поможет пользователю при заполнении формы.
Теперь о двух хитрых моментах. Вы наверное заметили две ссылки в начале формы. Этот ловкий прием позволит нашей формы вести себя правильно при работе с якорями (anchors).
Второй момент связан с применением шрифта с иконками. Мы будем использовать data-attribute, чтобы отобразить иконки. Устанавливая параметр data-icon=”icon_character” с соответствующим символов в HTML, мы должны назначить лишь одно правило в CSS для установления стиля всех иконок. Подробнее об этом приеме можно почитать на сайте: 24 Ways: Displaying Icons with Fonts and Data- Attributes.
Для чистоты кода я пропущу базовые параметры (html, body и т.п.), но вы сможете найти их в исходных файлах. Повторяю, что я использую приемы CSS3, которые не будут работать во всех браузерах. Итак, давайте же приступим!
Стилизуем формы, используя CSS3
Во-первых, давайте назначим нашим формам базовый стиль.
Мы добавили две тени к элементу: одна — с целью создать внутреннее голубое свечение, а вторая — внешняя тень. Чуть позже я объясню вам z-index.
Здесь мы назначим свойства для шапки:
Замечу, что сегодня только браузеры с webkit поддерживают background-clip: text, поэтому мы сделаем полосатый фон только для webkit и привяжем его к заголовку H1. Так как параметр background-clip: text работает только в Webkit браузерах, я решил работать только со свойствами webkit. Именно поэтому я разделил CSS на две части и использовал только градиент webkit. Однако вы не должны использовать лишь webkit на своих вебсайтах! Так, например, параметр -webkit-text-fill-color: transparent позволяет нам иметь прозрачный фон, но только для браузеров webkit, все другие браузеры проигнорируют это свойство.
Мы также создали тонкую линию под заголовком с помощью элемента :after pseudo-class. Мы использовали градиент с 2px в высоту и уменьшили прозрачность по краям до нуля.
Теперь давайте позаботимся о полях ввода и придадим им приятный вид.
Во-первых, мы стилизуем поля и уберем обводку. Но будьте осторожны: обводка помогает пользователю понять, на каком поле он находится. Если же вы уберете ее, то нужно применить свойства :active и :focus.
Здесь мы использовали псевдо класс :not, чтобы стилизовать все поля, кроме чекбоксов. Кроме того, я решил убрать обводку и добавил свойства :focus и :active.
Теперь время веселиться: шрифт с иконками. Так как мы не можем использовать псевдо-классы :before и :after, мы добавим иконку в параметр label, а затем разместим в поле. Я буду использовать библиотеку fontomas. Вы можете сами сопоставить иконки с соответствующей буквой. Помните атрибут data-icon? Именно в него нужно вставить букву. Я использовал data-icon=’u’ для логина, ‘e’ для email, ‘p’ для пароля. Как только я выбрал буквы, я скачал шрифт и использовал генератор шрифтов fontsquirrel для конвертации в формат, пригодный для @font-face.
Вот собственно и все. Вам не требуется иметь отдельный класс для каждой иконки. Мы использовали параметр content: attr(data-icon), чтобы получить букву из атрибута data-icon. Таким образом, нам нужно лишь назначить шрифт, выбрать цвет и разместить иконку.
Теперь назначим правила для кнопки отправки формы.
Трюк заключается в том, чтобы использовать box-shadow, чтобы создать несколько рамок. Естественно, вы можете использовать лишь одну рамку, но также можно и несколько. Мы будем использовать параметр length для создания “фейковой” второй белой рамки, 3px в ширину, без размытия.
Теперь стилизуем чекбокс, здесь мы ничего необычного не сотворим:
Стилизуем подвал формы, используя множественные линейные градиенты, чтобы создать полосатый градиент.
Сейчас вы видите, что у нас две приятные формы, но ведь мы хотим, чтобы отображалась только лишь одна из них. Пришло время анимации!
Создаем анимацию
Первое, что мы сделаем, мы спрячем вторую форму, назначив opacity на 0:
Помните, что форма входа имеет параметр z-index: 22? Второй форме мы назначим этот параметр на 21, чтобы поставить его “под” форму входа.
Теперь самое интересное: меняем формы местами, используя псевдо класс :target. Вам нужно понять одну вещь по поводу :target: для перемещения мы будем использовать якоря. Нормальное поведение якоря — прыжок на определенный элемент страницы. Но мы не хотим этого, мы лишь хотим поменять формы местами. И тут приходит на помощь наш трюк с использованием двух ссылок в начале страницы. Вместо того, чтобы направить нас прямо на вторую форму, рискуя испытать эффект “прыжка”, мы придадим ссылкам параметр display: none. Это поможет избежать прыжков. Я обнаружил этот трюк на сайте: CSS3 create (французский язык).
Вот, что происходит: когда мы кликаем на кнопку Присоединиться, мы направляемся на #toregister. Затем происходит анимация и лишь потом переходим на элемент #register. Мы используем анимацию под названием fadeInLeft. Так как мы “прячем” форму, используя нулевую прозрачность, мы применим анимацию, которая будем постепенно появляться. Мы также изменили z-index, чтобы она появилась поверх другой формы. То же самое происходит для другой формы same happens for the other form.
Вот код для анимации. Мы использовали CSS3 animation framework от Dan Eden и адаптировали этот фреймворк под наш туториал.
Форма, которая “исчезает”, будет иметь анимацию затемнения влево:
Вот и все, друзья. Надеюсь вам понравился этот туториал!
Заметим, что в некоторых браузерах параметр background-clip: text не поддерживается. В Internet Explorer 9 анимации не работают. В Internet Explorer 8 и ниже псевдо-класс :target pseudo-class не поддерживается, поэтому там этот эффект вообще работать не будет.
Авторизация на сессиях своими руками. Делаем логин в админке
Сначала выберем проект, в котором будем делать авторизацию. Сначала я хотел сделать отдельный, но потом подумал, а зачем? У нас есть админка интернет-магазина, которая прекрасно подойдет для экспериментов. Админка написана на vue.js, но если вы им не интересуетесь, не беспокойтесь. Мы сделаем так, чтобы авторизацию можно было прикрутить к любому проекту. Не копипастнуть, конечно, но весь код можно будет переиспользовать.
Давайте начнем. Осторожно, это прям лонгрид.
Мы будем писать код на php, как обычно, а авторизацию сделаем на сессиях. Если описать все одной строчкой кода, то вот
Так мы авторизовали пользователя. Серьезно, это самый важный код. Но есть и другие вопросы:
Если я еще вас не напугал, то это очень здорово. Устраивайтесь поудобнее, сейчас мы шаг за шагом разберемся со всеми вопросами. Разговор будет долгий.
Для начала определим в общих чертах, как это будет работать у нас.
Общая схема авторизации в админке
Прямо сейчас у нас есть админка интернет-магазина на vue, которая по адресу http://
Напомню, как она выглядит
Мы хотим, чтобы доступ к ней был только у авторизованных пользователей. А сначала юзеры должны видеть страничку логина. Вот так она будет выглядеть
Это простейшая страница с двумя полями ввода: логин и пароль. И единственная кнопка «Войти в админку».
Регистрацию мы делать не будем, это отдельная эпопея. Регистрацией, отправкой на почту писем с подтверждением и восстановлением пароля мы займемся, когда дойдем до личного кабинета. Разграничивать права пользователей тоже не будем. Это интересная задача, но мы сначала хотим разобраться с самой авторизацией, а уже потом копать дальше.
Если мы не будем динамически заводить пользователей, то значит, забьем их заранее. Это сильно упростит задачу, а функционал не пострадает. В конце концов, сколько там будет админов самописного интернет-магазина? Скорее всего один или два. Без разграничения прав заводить больше пользователей особого смысла нет. Вот мы и заведем всего двоих 🙂
Вернемся к форме логина. При нажатии на кнопку мы отправим логин и пароль на сервер, сделаем специальный запрос для этого. На сервере функция логина проверит, есть ли у нас юзер с такими данными. Если есть, то мы авторизуем этого юзера и пропишем его в сессию, чтобы при перезагрузке страницы не пришлось вводить логин-пароль заново. Если такого юзера нет, то есть логин или пароль неверные, то вернем в браузер ошибку и выведем в форме логина соответствующее сообщение. А еще реализуем разлогинивание, чтобы все как у людей.
Вот такой план. По идее, задача авторизации серверная, но мы будем писать так, чтобы с каждым новым куском кода был виден прогресс. Чтобы можно было тыкать кнопочки и проверять, что все идет как задумано. Поэтому начнем работу с клиентской части и по мере необходимости будем писать нужные куски на php. А также между делом рассуждать о паролях, хэшированиях, сессиях и прочих важных штуках.
Заменяем index.html на index.php
Создадим в корне админки (папке admin/vue/) папку templates и перенесем в нее файл index.html. А в корне создадим index.php с таким содержимым
Теперь у нас все работает, как и раньше. В этом можно убедиться, зайдя на ваш локальный сервер, у меня это http://w-shop.lc/admin/vue/. Если php работает нормально, то мы увидим страницу товаров в админке.
Идем дальше, нужно сделать страницу логина.
Создаем страницу логина login.html
Это отдельный html-файл, который лежит в той же папке templates рядом с index.html. Давайте сделаем простую html-заготовку для нового файла. В секции head напишем так. Прошу извинить, приходится писать html-теги с тупыми _, чтобы браузер не сильно ругался.
Пока ничего лишнего, это просто заглушка. Стили для css подключаем из cdn minicss, как и во всей админке. В body просто заголовок и 2 подключенных скрипта: jquery и login.js. Содержимое login.js
Теперь у нас есть 2 шаблона и мы можем написать заглушку для проверки авторизации пользователя.
Заглушка для авторизации
То есть мы подключали шаблон статично. А стало так
Мы подключили модуль авторизации и вывели шаблон в зависимости от результата функции isLogged. Не беда, что сейчас в ней просто return false, допишем код в нужное время. А пока можно еще раз проверить, что мы движемся верно: поменять return false на true и убедиться, что в зависимости от результата мы показываем шаблон index или login.
Как проверим, оставим return false и продолжим работать со страницей логина. Пора добавить в нее форму авторизации и написать javascript-код.
Добавляем форму логина
Как мы договаривались, в форме будут 2 инпута (логин и пароль) и кнопка «Войти». С учетом стилей фреймворка minicss это будет выглядеть так
С html все, пора написать javascript-код.
Авторизация на клиенте
Что же нужно сделать на клиенте? Отправить ajax-запрос с логином и паролем, дождаться ответа и если прилетит ошибка, вывести ее в форме. С клиентской валидацией мы в этот раз связываться не будем. Отправим логин-пароль как есть, хоть пустые. Пусть что нужно, сервер проверяет. Пишем код.
Сначала заведем объект ui, куда сложим нужные элементы dom
Затем конфиг, где укажем url, по которому будем пытаться авторизоваться
Дальше вспомним про обработку ошибок, точнее про показ и скрытие ошибки. Напишем 2 вспомогательные функции
В первую функцию передаем message, чтобы было какой текст показать. И снимаем с элемента error класс hidden. В функцию скрытия ошибки передавать нечего, просто навешиваем обратно hidden.
Дальше идем в функцию init и вместо бесполезного console.log напишем полезные навешивания событий
Осталось реализовать _login
Что здесь интересного?
Это весь код клиентской части. Неважно, какой способ авторизации на сервере вы выберете, этот код на клиенте подойдет для любой авторизации.
А теперь минутка философии.
Можно ли передавать логин и пароль по сети в открытом виде?
Поставьте ssl-сертификат и все. Это недорого, устанавливается несложно, а некоторые хостеры вообще предлагают бесплатные сертификаты, например, от Let’s Encrypt. Сам так делаю и голова не болит.
Едем дальше, теперь будет только серверный код.
Роутер для авторизации на бекенде
Итак, разбираемся с роутером auth. Для начала в файле /admin/api/v1/index.php подключим файл common/auth.php, где у нас будет вся работа с авторизацией.
Теперь создадим файл роутера routers/auth.php с таким содержимым
Как я предупреждал, подробное разъяснение этих строчек было в двух указанных выше статьях. Если расшифровать, то код говорит нам такое. Если на бекенд придет post-запрос /auth/login с двумя непустыми параметрами user и password, то нужно запустить функцию login() из пространства имен Auth. Если авторизация прошла успешно (code == success), то просто отдать клиенту json с 200 http-кодом ответа (он отдается по умолчанию). Если же авторизация не успешна, то отдать тот же json, но с 401 кодом ошибки (вот его нужно явно прописывать через header)
Чтобы зарегистрировать новый роутер в системе, добавим его в белый список в файле common/helpers.php в методе проверки на валидность. Теперь он будет выглядеть так
С роутером разобрались, посмотрим на саму функцию login. Идем в файл common/auth.php и добавляем заглушку для этой функции.
Не расстраивайтесь, что мы пишем уже не первую заглушку. Скоро мы их разгребем и заменим реальным кодом. А пока сделаем простейшую проверку на тупое совпадение строк логина и пароля.
Если совпадает, вернем массив, который роутер преобразует в json
Если не совпадает, то выходной json будет
В случае успеха никаких дополнительных данных не требуется. А в случае отказа дополнительно отправляем сообщение, которое покажем пользователю в форме логина.
Здесь еще дополнительно можно провести разные проверки, например, чтобы логин и пароль не были пустыми или слишком короткими. И по результатам валидации выводить соответствующие ошибки клиенту. Благо что для этого предусмотрено поле message. Можно, но я доверю это вам, а в примере оставлю только общую ошибку «не шмогла»
После этого кода можно уже потыкаться в форму логина и проверить связь клиента и сервера. Если все сделали правильно, то на ошибочные логин-пароль вы увидите красное сообщение. А если введете admin/password, то успешный alert(‘success’) и перезагрузку страницы в браузере. Конечно, после перезагрузки мы все еще будем видеть страницу логина. Непосредственно авторизация пользователя будет позже.
Что делать дальше?
И вот мы подбираемся к самому интересному: а где хранить пароли и в каком виде? Давайте сначала подумаем, где их хранить.
Разбираемся дальше, а в каком виде?
Способы хранения паролей
Второй риск похож на первый. Если у вас утащат базу с паролями, то велик шанс, что эти ушлые ребята гораздо больше соображают в шифровании и взломе, чем вы. Мы же не считаем, что сможем сделать самое надежное в мире шифрование, правда?
Подытожим, в тему шифрования я соваться пока не хочу и вам не советую. Есть способы надежнее и проще.
Как обойтись без шифрования. Хэширование
Фокус в том, что не нужно хранить пароли в открытом виде, но и не нужно шифровать их с возможностью расшифровки. Пароли нужно хэшировать и в базе хранить не пароль, а его хэш. Хитрым образом закодированную строку, которую нельзя расшифровать. Например, не password, а 5f4dcc3b5aa765d61d8327deb882cf99
Например, есть простая функция хэширования md5. Вот так она работает
Вот такие наборы символов и будем хранить в базе. А сравнивать с этой дикой строкой будем не пароль, а хэш пароля. Примерно так
Вот такая идея. Мы и не знаем пароль, даже если и получим его хэш, но можем проверить его правильность. То, что нужно.
Выбираем правильное хэширование
Идею хранения паролей нашли, то есть хранения не паролей, а их хэшей. А вот какой алгоритм хэширования выбрать?
Помимо сложности самого алгоритма, есть и другой момент. Да, расшифровать пароль по хэшу нельзя, но его можно подобрать. Простым брутфорсом. К тому же существуют многочисленные базы паролей md5, где всевозможные варианты хранятся тупо списком. И подбор вашего пароля по известному хэшу займет столько времени, сколько понадобится для выполнения sql-запроса
Конечно, вы сами не будете использовать пароль 123456, но как насчет ваших пользователей? Да, 123456 можно подобрать и руками, но в таком случае никакие алгоритмы не помогут. Наша же задача максимально позаботиться о юзерах, которые выбирают пароли сложнее qwerty. Думаем дальше, гуглим.
Помимо md5 есть множество алгоритмов хэширования, sha256, sha512 и еще целая толпа. Их сложность выше, но это не отменяет опять-таки существования таблиц с готовыми паролями. Нужно что-то хитрее.
Этот кулинарный термин активно применяется в теме хэширования. В чем суть?
А никак. Человек скорее убежит с сайта, чем будет сочинять пароль, удовлетворяющий десятку ваших требований. Сам так делал (сбегал). Поэтому не нужно заставлять пользователей, нужно самим добавлять к их паролям те самые странные наборы символов.
То есть вводит юзер пароль qwerty, а мы добавляем к нему какой-то дикий набор, например,
То есть вместо qwerty получаем
И уже эту странную строчку хэшируем. Так намного меньше шансов, что пароль легко будет подобрать, имея на руках хэш. Во-первых, он длиннее, а во-вторых, там есть лишний набор случайных символов. Вот этот набор и называется солью.
Когда мы будем сравнивать введенный пароль с хэшем, то нам нужно будет опять-таки прибавить эту соль к строке и уже ее хэшировать.
Здесь возникают сразу 3 вопроса:
1. откуда брать эту соль
2. как ее хранить
3. как все-таки хэшировать, раз md5 и прочие sha512 не подходят
Чтобы повысить надежность, можно комбинировать подходы. Например, прибавить к паролю статичную соль и динамическую, которую затем положить в таблицу. Динамическую соль можно получить, например, как md5(user). Да, сам по себе md5 небезопасен, но добавляя соли и применяя md5 несколько раз, надежность хэширования увеличивается.
Здесь уже можно извращаться как угодно. Вот варианты для хэша пароля
Вариантов, как видим, множество, все зависит только от нашей фантазии и паранойи. Еще раз уточню, если будете использовать такой подход, то выбирайте вместо md5 что-нибудь понадежнее, например, sha512. Ранние версии вордпресса вообще использовали просто md5(password), но со временем сложность хэширования возрастала. Где-то читал, что некоторые cms применяли md5 к паролю аж 64 раза! Основательный подход.
Как же хэшировать нам?
Подход с формулой вроде md5(md5(password) + md5(user)) мне кажется вполне адекватным. Прямо такую брать не стоит, наверняка для нее существуют подборки паролей. Но можно ее усложнить, применив хэш еще несколько раз.
password_hash по умолчанию использует сильный алгорим шифрования, который меняется на еще более сильные в новых версиях php. Для каждого пароля генерируется случайная соль, которую не нужно хранить отдельно. Соль можно задать и руками, но это категорически не рекомендуется. В конце-то концов, люди, создавшие эти алгоритмы, соображают в безопасности гораздо больше меня, который разобрался только в самых азах. Зачем городить свое, если можно воспользоваться наработками специалистов?
Вы спросите, а на фига же мы тут на трех страницах рассуждали о паролях, солях и хэшах, если можно просто взять и сделать так?
А потом сравнить пароли так
Но я верю, что мои статьи читают разные люди. Одним нужно просто решить задачу. Они копипастят код и интегрируют его в свой проект. В этом нет ничего плохого.
Но есть и другие. Те, которым интересно разобраться, какие вообще бывают подходы и почему мы пришли именно к такому. Для вас я и пишу такие простыни текста и надеюсь, что кому-то это будет полезно или интересно. Или откроете что-то новое для себя. А если сделаете еще лучше, чем реализовал я, то это вообще классно. Вот этом случае статья точно будет написана не зря.
Хорошо поговорили, но давайте завязывать с парольной философией и перейдем к коду.
Добавляем таблицу admin_users и пользователей с паролями
Как мы договорились в начале статьи, регистрацией заниматься не будем, поэтому заведем руками двух пользователей нашей админки. Сначала sql-запрос для создания самой таблицы
Теперь добавим в таблицу 2 строки:
Теперь когда у нас есть данные в базе и мы знаем, как проверять правильность пароля, мы можем вместо заглушки функции логина написать нормальный код.
Реализуем функцию логина
Идем в файл common/auth.php и смотрим на заглушку
Теперь вместо тупой проверки в лоб нам нужно провести действия похитрее. Вытащить из базы хэш пароля по имени пользователя и проверить его с помощью password_verify.
Я не буду описывать функции подключения к базе, это все расписано в серверном уроке админки. Да, знаю, в пятый раз уже даю ссылку, но это лучше, чем копипастить сюда все объяснение кода, совсем не маленькое. Поэтому мы воспользуемся готовым, написанным ранее кодом. Впрочем, при необходимости вы сами легко вытащите данные из базы любым удобным способом. У нас же обновленный код функции получится таким
Если пользователя с таким именем в базе нет, то массив будет пустой.
Вывод результата остается таким же, меняется лишь условие проверки. Вместо старого
напишем честную проверку хэша через password_verify
Вот так. Теперь функция login возвращает нам такие же данные, но идет нормальная проверка на совпадение логина и пароля. Можно попробовать в интерфейсе и убедиться, что admin/password по прежнему подходят, хоть мы и перенесли данные в базу. Но теперь еще подходит и вторая пара developer/qwerty. Все работает как надо.
Мы научились заводить пользователей в базу, пусть и руками. Научились проверять правильность логина и пароля. Но осталось главное, ради чего все и затевалось. Нам нужно уметь запоминать пользователей, которые ввели верный логин и пароль. И не терять эту информацию при перезагрузке страницы. В этом нам поможет механизм сессий.
Что такое сессии?
Попробую рассказать в паре абзацев.
1. Ее может сбросить сам пользователь, удалив куку PHPSESSID
2. Сессия протухнет сама через определенное время, когда мы закроем браузер. Обычно по дефолту 24 минуты
3. Мы сами сбросим сессию через php-код. Этим приемчиком мы воспользуемся, когда будем реализовывать разлогинивание
Если хотите разобраться с сессиями подробнее, можно дополнительно загуглить. Статей на эту тему написано множество. Также есть много тонкостей, не зная которых, можно долго искать, почему сессии не работают. Но того малого, что я рассказал, достаточно для авторизации. А о некоторых тонкостях работы с сессиями я расскажу в процессе.
Давайте же пробовать на практике.
Пишем код непосредственной авторизации на сессиях
Сначала сделаем так, чтобы при успешной проверке логина-пароля в сессию записывались данные об авторизации. Смотрим опять функцию login, там, где идет проверка условия password_verify. И в блоке if перед возвратом массива с code = success дописываем такую строку
То есть блок if будет выглядеть так
Именно эта новая строка и «логинит» пользователя. В сессию мы запишем id юзера. В нашей админке можно было обойтись просто булевым флагом authorized, но часто бывает, что айдишник оказывается очень нужной штукой. Например, если нам понадобится вытащить из базы email пользователя, чтобы отправить ему письмо, или имя, чтобы написать в шапке сайта что-то вроде «Привет, Вася!»
Есть соблазн закинуть все нужные данные в сессии, но не стоит увлекаться этим. Сессии не резиновые и занимают место. Лучше сохранить только id, а при необходимости доставать нужные данные из базы.
Но это мы немного отвлеклись. Данные в сессию мы сохранили, но еще нужно стартовать сам механизм сессий. Делается это с помощью функции session_start. У ней есть одна хитрость. Вызывать ее нужно до того, как мы вывели в браузер хоть что-то, хоть html, хоть json, хоть пустой пробел. То есть ставьте вызов session_start как можно выше. Часто его ставят просто в начале php-шного файла.
Вообще без неободимости запускать сессии не стоит. То есть пока у нас сессия используется только в функции login, вроде бы и стартовать сессии нужно только там. Но я чуть забегу вперед и скажу, что нам понадобится, чтобы сессии работали при любом апишном запросе. Чуть позже разберем, почему, а пока просто зафигачим код в начало admin/api/v1/index.php
Есть еще один момент. Сессии работают так, что запускать их нужно только один раз. Повторный запуск session_start выкинет ошибку. У нас работает все правильно, запускаем только один раз, но я предпочитаю подстраховаться и перед запуском проверить, а не была ли сессия уже запущена. Делается это с помощью функции session_id(), вот так
Вот теперь у нас безопасный старт сессии. Если даже выше по коду мы где-то уже стартанули сессию, то эта проверка защитит от повторной инициализации.
Теперь пользователь залогинен, осталось научиться это понимать. Вспомним функцию isLogged, которую мы написали в самом начале, поставив там заглушку return false. Давайте это исправим и напишем реальный код
Вот так, ничего сложного. Функция проверяет, существует ли сессия userId и не равна ли она пустой строке. Напомню, userId у нас всегда число.
Идем дальше. Ищем файл admin/vue/index.php, тот самый главный, который разруливает, какую страницу показывать: админки или форму логина. Вот он
Разлогинивание
В любой порядочной админке нужно уметь не только входить, но и выходить из нее. После того, что мы сделали для авторизации, разлогин покажется нам очень простым. Сначала определимся с роутером. Заведем новый роут для /auth/logout в файле routers/auth.php
Дальше пишем код для logout в файле common/auth.php
API для выхода готово, осталось только разместить соответствующую кнопку в шапке админки. В компоненте AppHeader.vue после табов разместим ссылку
Готово, можно пробовать разлогиниться. И логиниться заново под вторым пользователем.
Закрываем API для неавторизованных пользователей
Мы молодцы и в админку теперь можно попасть только зная логин и пароль. Но апишные запросы, те самые получения списка товаров и брендов и все редактирование брендов остается открытым. Можете проверить. Сначала выйдите из админки, то есть разлогиньтесь. При заходе на http://w-shop.lc/admin/vue/ вы увидите форму логина, а вот если дернете прямо в браузере http://w-shop.lc/admin/api/v1/products, то получите полный список товаров. То же самое и с остальными запросами.
Напишем вот такой код в /admin/api/v1/index.php после подключения всех файлов, но перед проверкой роутера на валидность
Две проверки в условии, если не прокатывают, то вернем клиенту 403 ошибку и завершим работу. Второе условие очевидно, мол, если пользователь не авторизован. А первое чуть хитрее, роутер не должен быть auth. Почему? А потому, что без этого условия мы закроем доступ к апишной функции логина, а она должна быть как раз открыта всегда. На самом деле она нужна только для неавторизованных юзеров, но не будем усложнять, особой роли это не играет.
Мы сделали все, что касается авторизации, но остался один момент. У нас админка на vue, а работает ли оно все как надо?
Проверяем работоспособность vue
Вроде бы, чего там может сломаться? Нам же практически не пришлось лезть в код vue, за исключением добавления кнопки Выйти в шапке админки.
Но попробуем пересобрать админку, чтобы убедиться, что все хорошо. Сначала в production режиме
Но при разработке нам гораздо важнее режим девелопера, который предоставляет vue-cli. Попробуем запустить его
Опа, открылся http://localhost:8080/, но вернул 404 ошибку с текстом «Cannot GET /». Что за фигня?
Дело в том, что vue-cli при запуске ищет входной файл index.html, который располагается в корневой папке /admin/vue, рядом с конфигом вебпака. А у нас там нет index.html, только index.php. А index.html вместе с login.html мы вынесли в отдельную папку templates.
Почему же, когда мы сбилдили приложение в production режиме и зашли через нормальный хост http://w-shop.lc/admin/vue/, то все было хорошо? Скорее всего, потому что в настройках вашего домена в nginx или apache первым читается файл index.php. Чаще всего так и делают. Например, в nginx у меня было так
То есть, в первую очередь веб-сервер должен искать index.php, если его нет, то index.html.
Так вот, первая проблема, что vue-cli работает в обход внешнего веб-сервера и ищет index.html. Ему пофиг, что в nginx указан index.php. А html-файл у нас лежит в templates.
Если вы знаете хорошее решение, то поделитесь им в комментариях, а я пока расскажу свой костыльчик.
Да, еще в login.html нужно поправить путь до login.js, мы же его переместили в src
Но нас ждет еще один сюрприз. В dev режиме шаблон-то подхватывается, но админка пустая, все апишные запросы отдают 403 Forbidden. Почему? Давайте посмотрим на код в /admin/api/v1/index.php, где это может быть. А вот здесь
Правильно, мы не проходим второе условие isLogged, проверку на залогиненность. Вот даже комментарий оставили «Закрываем API для неавторизованных пользователей». А сейчас мы в dev режиме открыли админку в обход авторизации. А чтобы заработали апи-запросы, обернем этот код еще в одно условие
Вот и все. Больше кода в этом уроке не будет. Поздравляю, если дочитали до конца 🙂
Вместо заключения
В целом я не гнушаюсь такими хаками системы, но лучше от них избавляться. Такие решения не всегда очевидные и через месяц мы можем забыть, зачем это вообще сделали. Да, комментарии облегчают жизнь, но все равно мы не застрахованы от того, что в будущем подобный хак выстрелит нам в ногу.
Именно поэтому, разбираясь с проблемами dev режима, я начал жалеть, что вместе с vue не стал изучать, например, laravel. Это отличный php-фреймворк, который дружит с vue. Думаю, в этой связке проблем с авторизацией нет. Или они решаются более приличным способом.
Тем не менее, наша авторизация вполне рабочая и довольно компактная. Если честно, когда я засел за реализацию, то не ожидал, что кода окажется так мало. Гораздо больше усилий заняло собрать в кучу разные наработки и отбросить лишнее. Ну и написать статью, могу ее назвать прямо лонгридом, давно не писал таких здоровенных. Но надеюсь, что-то из этой статьи вам было полезным, узнали что-то новое или вообще взяли для своего проекта всю реализацию целиком. Тогда все это было не зря.