пїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ
По вашему запросу ничего не найдено :(
Убедитесь, что запрос написан правильно, или посмотрите другие
наши статьи:
Сегодня подробно расскажем как найти практическое применение знаниям, полученным в статье про структуру asteriskcdrdb, а именно, как сделать ежедневные отчеты о входящих звонках на почту.
Создание скрипта
Чтобы наш .php скрипт смог подключиться к базе данных, необходимо создать пользователя, с правами, которые буду позволять ему извлекать необходимую информацию. Для этого, подключимся к нашему серверу по SSH
[root@asterisk]# mysql
mysql>CREATE USER ' user'@'localhost' IDENTIFIED BY 'P@ssw0rd';
На данном этапе мы создали пользователя user с паролем P@ssw0rd. Далее дадим ему необходимые права:
mysql> GRANT SELECT ON asteriskcdrdb.cdr TO 'user'
Создадим файл с расширением .php, в котором мы отразим подключение к нашей базе данных. Запишем эту конструкцию так:
$hostname = "localhost"; //адрес хоста. Скрипт мы будем запускать на той же машине, на которой находится БД asteriskcdrdb;
$username = "user"; //отражаем пользователя
$password = "P@ssw0rd"; //пароль для созданного нами пользователя
$dbName = "asteriskcdrdb"; //база данных, в которой хранятся необходимые нам данные
$today = date('y-m-d'); // сегодняшняя дата в формате 2016-03-25
$counter = 1; // счетчик
mysql_connect($hostname,$username,$password) OR DIE("Не могу создать соединение "); // соединиться к БД
mysql_select_db($dbName) or die(mysql_error()); //выбрать базу данных. Если произойдет ошибка - вывести ее
$headers = "; charset=windows-1251
"; //заголовок для письма
$headers .= "From: Мерион Нетворкс <info@merionet.ru>
";
$headers .= "Reply-To: info@merionet.ru
";
Предположим, что все входящие звонки приходят на номер секретаря – 100. Так же мы знаем, что при звонке из города, мы видим номер звонящего, который содержит в себе больше 3 символов (пусть у нас используется трехзначная внутренняя нумерация). Наша задача сводится к формулировке запроса к таблице cdr. Добавляем к нашему .php файлу:
$query = "SELECT `dst` , `src` , `duration` , `dstchannel` , `calldate` , `disposition` FROM `cdr` WHERE `calldate` >='$today 00:00:00' AND `calldate` <='$today 23:59:59' AND LENGTH( `src` ) >3 AND `dst` = '100';" ;
$res=mysql_query($query) or die(mysql_error()); // Выполнить запрос. Если произойдет ошибка - вывести ее.
$number = mysql_num_rows($res); // Как много нашлось строк
У нас почти все готово. Осталось только обработать данные на выходе. Для этого, нам понадобится следующая конструкция:
//формируем шапку нашей таблицы со значениями
$mes .= '
table style="max-width: 575px;border-bottom:none; margin: 0 auto;border-spacing: inherit;">
thead>
tr style="border-bottom: 2px solid #05477c;">
th style="padding:10px; color: #fff; max-width: 150px;background:#05477c;">Порядковый номер</th>
th style="padding:10px; color: #fff; max-width: 150px;background:#05477c;">Дата</th>
th style="padding:10px; color: #fff; max-width: 100px;background:#05477c;">От кого</th>
th style="padding:10px; color: #fff; max-width: 45px;background:#05477c;">Кому</th>
th style="padding:10px; color: #fff; max-width: 45px;background:#05477c;">Статус звонка</th>
/tr>
/thead>';
//перебираем значения ассоциативного массива. Число элементов данного массива равно числу строк на выходе sql запроса
while ($row=mysql_fetch_array($res)) { $mes .= '
tbody>
tr style="width: 100px;">
td style="padding:10px; border-bottom: 1px solid #eee; text-align:center;">'.$counter.'</td>
td style="padding:10px; border-bottom: 1px solid #eee; text-align:center;min-width: 100px;">'. $row['calldate'].'</td>
td style="padding:10px; border-bottom: 1px solid #eee; text-align:center;min-width: 100px;">'. $row['src'].'</td>
td style="padding:10px; border-bottom: 1px solid #eee; text-align:center;">'.$row['dst'].'</td>
td style="padding:10px; text-align:center; border-bottom: 1px solid #eee; min-width: 120px; ">'.$row['disposition'].'</td>
/tr>';
$counter = $counter + 1;
}
Теперь, мы храним в переменной $mes html таблицу, которая готова к отправке на почту. Добавим в конец скрипта:
mail("info@merionet.ru", 'Все входящие за '.$today.'', $mes, $headers);
ВАЖНО! Если вы используете кириллические символы, установите кодировку .php файла на Кириллицу (windows-1251)
Итак, готово. Давайте посмотрим что приходит нам на почту:
Работает. Давайте сделаем ежедневное задание на отработку этого скрипта через cron. Сделаем, например, ежедневно, в 17:30, когда рабочий день подходит к концу:
30 17 * * * php /home/admin/mail_report.php
Не забудьте в начала скрипта поставить открывающий тэг php, а в конце скрипта закрывающий.
Киберпреступность — это печальная реальность современности, затрагивающая как частных пользователей, так и бизнес. Ни одна компания или организация не застрахована, и ситуация вряд ли улучшится в ближайшее время. Эксперты прогнозируют, что убытки от киберпреступлений достигнут $25 трлн к 2025 году. Forbes также предупреждает об увеличении угроз для мобильных устройств.
Эти прогнозы подчеркивают, что киберпреступность останется с нами и будет только расти. В связи с этим цифровой мир стремится разрабатывать новые стратегии для усиления кибербезопасности.
В этой статье мы рассмотрим протокол аутентификации Kerberos и узнаем, как он работает.
Что такое Kerberos?
Kerberos — это протокол безопасности компьютерных сетей, который аутентифицирует запросы между двумя или несколькими доверенными хостами в ненадежной сети, такой как интернет. Разработанный MIT для проекта Athena в конце 1980-х, он теперь используется по умолчанию в Microsoft Windows и реализован в других операционных системах, таких как Apple OS, FreeBSD, UNIX и Linux.
Как работает Kerberos
Kerberos использует криптографию с секретным ключом и доверенное третье лицо — Центр Распределения Ключей (KDC) — для аутентификации клиент-серверных приложений и проверки идентичности пользователей. KDC предоставляет услуги аутентификации и выдачи билетов, которые обеспечивают безопасную проверку идентичности, защищая от прослушивания и повторных атак.
Для чего используется Kerberos
Kerberos широко применяется в цифровом мире, особенно в системах, требующих надежного аудита и аутентификации. Он используется в аутентификации Posix, Active Directory, NFS и Samba, а также как альтернатива системам аутентификации SSH, POP и SMTP.
Основные применения Kerberos
Единый вход (SSO). Kerberos позволяет пользователям аутентифицироваться один раз и получить билет, известный как Kerberos ticket-granting ticket (TGT). Этот TGT можно использовать для запроса билетов на доступ к различным ресурсам без повторного ввода учетных данных, что упрощает работу пользователей и снижает необходимость управления множеством паролей.
Сетевая аутентификация. Kerberos предоставляет безопасный механизм для проверки подлинности сетевых служб, таких как серверы и приложения. Клиенты могут запросить билет на службу у Центра Распределения Ключей (KDC) с использованием своего TGT, а этот билет используется для аутентификации и установления защищенной сессии с запрашиваемой службой.
Взаимная аутентификация. Kerberos обеспечивает взаимную аутентификацию, что означает, что и клиент, и сервер аутентифицируют друг друга в процессе начальной аутентификации. Это предотвращает impersonation и атаки "человек посередине" путем проверки подлинности обеих сторон в коммуникации.
Авторизация. Kerberos также может использоваться для реализации политик контроля доступа. После аутентификации клиента Kerberos билет содержит информацию о его идентичности и правах доступа. Серверы могут использовать эту информацию для применения правил авторизации и предоставления или отказа в доступе к конкретным ресурсам в зависимости от привилегий клиента.
Что делает протокол аутентификации Kerberos?
MIT разработал протокол для проекта под названием Athena. Название происходит от трехголового пса Адеса из греческой мифологии, который охранял ад. Имя было выбрано, потому что протокол Kerberos представляет собой три компонента:
Клиент
Сетевой ресурс (сервер приложений)
Центр распределения ключей (KDC)
Эти три компонента позволяют Kerberos обеспечивать аутентификацию доверенных хостов в ненадежных сетях. Kerberos гарантирует, что доступ к сетевым ресурсам имеют только авторизованные пользователи. Также он обеспечивает AAA безопасность: Аутентификацию, Авторизацию и Учет.
Разработчики MIT создали Kerberos для безопасной аутентификации к требуемым системам и авторизации пользователей. В то время большинство систем передавали незашифрованные пароли, что позволяло хакерам получить несанкционированный доступ. Поэтому разработка Kerberos была необходима.
Проектом занимались S.P. Miller, B.C. Neuman, J.I. Schiller и J.H. Saltzer.
В Kerberos KDC выдает билеты, которые позволяют различным хостам подтверждать свою личность. Также разработчики предусмотрели, что аутентификация Kerberos поддерживает авторизацию. Это значит, что клиент, аутентифицированный Kerberos, также получает доступ к ресурсам.
Преимущества аутентификации Kerberos
Kerberos приносит множество преимуществ в любую настройку кибербезопасности:
Эффективный контроль доступа. Kerberos позволяет пользователям отслеживать входы и применять политику безопасности через единую точку.
Ограниченный срок действия ключевых билетов. Каждый билет Kerberos имеет метку времени, данные о сроке действия и продолжительность аутентификации, контролируемую администратором.
Взаимная аутентификация. Системы и пользователи могут аутентифицировать друг друга.
Повторное использование аутентификации. Аутентификация пользователей Kerberos повторно используется и долговечна; каждый пользователь должен быть проверен системой только один раз. Пока билет действителен, пользователю не нужно повторно вводить свои данные для аутентификации.
Сильные и разнообразные меры безопасности. Протоколы безопасности Kerberos используют криптографию, несколько секретных ключей и авторизацию третьих сторон, создавая надежную защиту. Пароли не передаются по сетям, и все секретные ключи зашифрованы.
Как работают протоколы аутентификации Kerberos?
Ниже представлена упрощенная схема работы протоколов аутентификации Kerberos:
Запрос к серверу аутентификации. Клиент запрашивает аутентификацию у KDC. Этот запрос передается в открытом виде.
Ответ сервера аутентификации. KDC отправляет TGT и сеансовый ключ, если клиент есть в базе данных. Если клиента нет в базе, аутентификация не проходит.
Запрос билета на службу. Клиент запрашивает билет на службу вместе с TGT, выданным ранее KDC.
Ответ на запрос билета. KDC отправляет билет, зашифрованный сеансовым ключом. Клиент может использовать сеансовый ключ, отправленный ранее KDC, для расшифровки билета на службу.
Запрос к серверу приложений. Клиент запрашивает доступ к серверу приложений, используя билет на службу.
Ответ сервера приложений: Сервер приложений аутентифицирует клиента и отправляет билет, который предоставляет доступ к конкретной услуге.
Билет службы имеет определенный срок действия. Вы можете использовать один и тот же билет сеанса для доступа к службам до истечения срока его действия. По умолчанию срок действия билета Kerberos составляет 600 минут.
Обзор потока протокола Kerberos
Давайте подробнее рассмотрим, что такое аутентификация Kerberos, и разберем, как она работает, разделив ее на основные компоненты.
Основные участники типичного процесса Kerberos:
Клиент действует от имени пользователя и инициирует запрос на услугу.
Сервер предоставляет услугу, к которой пользователь хочет получить доступ.
Сервер аутентификации (AS) выполняет аутентификацию клиента. Если аутентификация успешна, AS выдает клиенту билет, называемый TGT (Ticket Granting Ticket). Этот билет подтверждает другим серверам, что клиент аутентифицирован.
Центр распределения ключей (KDC): в среде Kerberos сервер аутентификации логически разделен на три части: базу данных (db), сервер аутентификации (AS) и сервер выдачи билетов (TGS). Эти три части объединены в одном сервере, называемом Центром распределения ключей (KDC).
Сервер выдачи билетов (TGS) — это сервер приложений, который выдает билеты на услуги.
Теперь разберем процесс протокола.
Существует три ключевых секретных ключа, используемых в потоке Kerberos:
Ключ клиента/пользователя: хэш, полученный из пароля пользователя.
Секретный ключ TGS: хэш пароля, использованный для определения TGS.
Секретный ключ сервера: хэш пароля, использованный для определения сервера, предоставляющего услугу.
Процесс протокола включает следующие шаги:
Шаг 1. Начальный запрос аутентификации клиента: Пользователь запрашивает у сервера аутентификации (AS) билет TGT. Этот запрос включает идентификатор клиента.
Шаг 2. KDC проверяет учетные данные клиента. AS проверяет базу данных на наличие клиента и доступность TGS. Если AS находит оба значения, он генерирует секретный ключ клиента/пользователя, используя хэш пароля пользователя.
AS затем вычисляет секретный ключ TGS и создает сеансовый ключ (SK1), зашифрованный секретным ключом клиента/пользователя. AS генерирует TGT, содержащий идентификатор клиента, сетевой адрес клиента, метку времени, срок действия и SK1. Тicket TGS секретный ключ затем шифрует билет.
Шаг 3. Клиент расшифровывает сообщение. Клиент использует секретный ключ клиента/пользователя для расшифровки сообщения и извлечения SK1 и TGT, создавая аутентификатор, который подтверждает клиента TGS.
Шаг 4. Клиент использует TGT для запроса доступа. Клиент запрашивает билет у сервера, предоставляющего услугу, отправляя извлеченный TGT и созданный аутентификатор в TGS.
Шаг 5. KDC создает билет для файлового сервера. TGS использует секретный ключ TGS для расшифровки TGT, полученного от клиента, и извлечения SK1. TGS расшифровывает аутентификатор и проверяет, соответствует ли он идентификатору клиента и сетевому адресу клиента. TGS также проверяет метку времени, чтобы убедиться, что TGT не истек.
Если все проверки пройдены успешно, KDC генерирует сеансовый ключ услуги (SK2), который делится между клиентом и целевым сервером.
Наконец, KDC создает билет услуги, включающий идентификатор клиента, сетевой адрес клиента, метку времени и SK2. Этот билет шифруется секретным ключом сервера, полученным из базы данных. Клиент получает сообщение с билетом услуги и SK2, все зашифрованное с помощью SK1.
Шаг 6. Клиент использует билет услуги для аутентификации. Клиент расшифровывает сообщение с помощью SK1 и извлекает SK2. Этот процесс создает новый аутентификатор, содержащий сетевой адрес клиента, идентификатор клиента и метку времени, зашифрованный с помощью SK2, и отправляет его вместе с билетом услуги на целевой сервер.
Шаг 7. Целевой сервер принимает расшифровку и аутентификацию. Целевой сервер использует секретный ключ сервера для расшифровки билета услуги и извлечения SK2. Сервер использует SK2 для расшифровки аутентификатора, проверяя, совпадают ли идентификатор клиента и сетевой адрес клиента из аутентификатора и билета услуги. Сервер также проверяет билет услуги на предмет его истечения.
После успешного прохождения всех проверок целевой сервер отправляет клиенту сообщение, подтверждающее, что клиент и сервер аутентифицировали друг друга. Пользователь теперь может начать защищенную сессию.
Теперь, когда мы рассмотрели, что такое Kerberos, давайте перейдем к вопросу, является ли Kerberos безошибочным.
Понятия и термины объектов Kerberos
Большинство целей Kerberos связаны с управлением паролями. Он обеспечивает, чтобы пароли не передавались по сети и не хранились на клиентских системах; система удаляет их сразу после использования. Пароли не должны храниться в открытом виде, и каждая сессия должна использовать только один пароль.
Кроме того, вся информация об аутентификации хранится на централизованном сервере, что означает:
Администратор может ограничить доступ любого клиента из централизованного сервера.
Один пароль пользователя может обеспечить доступ ко всем службам.
Защита информации пользователя становится менее сложной, так как нужно защищать только один сервер.
В Kerberos все сущности должны аутентифицироваться друг у друга по запросу.
Следующие сущности используют протоколы Kerberos:
Принципы Kerberos — это уникальный идентификатор, назначаемый билету. Для большинства пользователей это тот же идентификатор, что и имя пользователя. Kerberos идентифицирует принципала по следующей информации:
Для пользователей: это имя пользователя; для хостов: слово "host". Для служб принципал — это название службы.
Дополнительный идентификатор, указывающий имя хоста.
Имя области Kerberos, в которой работает сервер Kerberos.
Серверы приложений Kerberos предоставляют доступ к ресурсам, которые нужны клиентам.
KDC Kerberos предоставляет доступ к ресурсам, таким как эмуляция терминалов и удаленные вычисления.
База данных Kerberos содержит записи о каждом принципале. Это централизованное хранилище Kerberos, содержащее идентификацию клиентов и их доступ.
Служба аутентификации Kerberos выдает билет TGT (Ticket Granting Ticket) клиентам.
Служба выдачи билетов Kerberos аутентифицирует клиентов на основе TGT.
После аутентификации пользователь получает билет аутентификации. Клиент может использовать этот билет для получения билетов на доступ к сервисам приложений.
Kerberos против других протоколов аутентификации сети
Существуют и другие протоколы аутентификации помимо Kerberos. Рассмотрим их:
Kerberos vs. Microsoft New Technology LAN Manager (NTLM): NTLM был предыдущей технологией, используемой Windows. С Windows 2000 все версии используют Kerberos. NTLM использует аутентификацию по принципу вызова-ответа: сервер задает вопрос, на который клиент должен ответить.
Kerberos vs. Lightweight Directory Access Protocol (LDAP): LDAP позволяет поддерживать информацию о пользователях. LDAP и Kerberos могут использоваться в одной сети: LDAP предоставляет службу авторизации, а Kerberos — аутентификацию.
Kerberos vs. Remote Authentication Dial-in User Service (RADIUS): RADIUS был предназначен для удаленного доступа пользователей через модемные соединения. Однако сетевые службы используют его для учета и аутентификации наряду с Kerberos.
Является ли Kerberos безопасным?
Теперь, когда вы знаете, что такое Kerberos, возможно, вас интересует, является ли он безопасным.
Специалисты по безопасности по всему миру считают Kerberos безопасным. Он использует сильное шифрование для защиты данных. Тем не менее, исследователи безопасности обнаружили несколько способов обхода Kerberos:
Атака "Pass-the-key": хакеры подделывают клиентов, используя их учетные данные.
Атака "Pass-the-ticket": хакеры используют билет, когда KDC отправляет сеансовый билет.
Атака "Golden ticket": хакеры используют контроллеры домена Windows для создания учетных данных клиента.
Может ли Kerberos быть взломан?
Ни одна мера безопасности не является на 100% неприступной, и Kerberos не является исключением. Поскольку он существует уже долго, хакеры имели возможность найти способы обойти его, обычно подделывая билеты, делая повторные попытки угадывания паролей (грубая сила/наполнение учетных данных) и используя вредоносное ПО для понижения уровня шифрования.
Тем не менее, Kerberos все еще является лучшим доступным протоколом безопасности. Протокол достаточно гибок, чтобы использовать более надежные алгоритмы шифрования для борьбы с новыми угрозами, и если пользователи придерживаются хороших политик выбора паролей, все должно быть в порядке!
Является ли Kerberos устаревшей системой?
Долговечность не обязательно означает устаревание. Несмотря на некоторые случаи, когда киберпреступники обходили Kerberos (и мы уже установили, что ни одна система безопасности не является на 100% неприступной), Kerberos по-прежнему активно используется и пользуется хорошей репутацией.
Часто задаваемые вопросы
Что такое Kerberos и как он работает?
Kerberos — это протокол сетевой аутентификации, который обеспечивает безопасную аутентификацию в распределенных вычислительных средах. Он использует доверенную третью сторону, называемую Центром распределения ключей (KDC), для аутентификации клиентов и серверов. KDC выдает билеты, которые подтверждают личность клиентов и серверов, позволяя безопасное общение и предотвращая несанкционированный доступ.
Как применяется Kerberos?
Один из примеров применения Kerberos — это система аутентификации, используемая в Microsoft Active Directory. Kerberos является основным протоколом для аутентификации в доменах Windows, позволяя пользователям безопасно получать доступ к сетевым ресурсам и службам.
Какие преимущества есть у Kerberos?
Некоторые преимущества использования Kerberos для аутентификации включают:
Сильная безопасность. Kerberos использует шифрование и взаимную аутентификацию для обеспечения целостности и конфиденциальности обмена аутентификацией.
Единая точка входа. После аутентификации пользователи могут получить доступ к нескольким службам и ресурсам без повторного ввода учетных данных, что повышает удобство и продуктивность.
Централизованная аутентификация. Kerberos предоставляет централизованную систему аутентификации, уменьшая необходимость в управлении отдельными учетными данными для каждой службы или системы.
Масштабируемость. Kerberos может обрабатывать крупные масштабные среды и поддерживает эффективную аутентификацию для большого количества пользователей и служб.
В чем разница между Kerberos и KDC?
Kerberos относится к самому протоколу сетевой аутентификации, тогда как KDC (Key Distribution Center) представляет собой централизованный сервер, который реализует протокол Kerberos. Он состоит из двух основных компонентов: Службы аутентификации (AS) и Службы выдачи билетов (TGS). AS отвечает за начальную аутентификацию и выдачу билетов TGT (Ticket-Granting Tickets), в то время как TGS выдает билеты на доступ к конкретным службам. В общем, Kerberos — это протокол, а KDC — серверная реализация этого протокола.
Как хороший разработчик на JavaScript, вы стремитесь писать чистый, надежный и поддерживаемый код. Возможно, вы замечали, что пишете код для одной задачи, а он похож на решение для совершенно другой проблемы, с которой вы могли сталкиваться ранее. Вы можете не знать об этом, но вы использовали паттерн проектирования.
Преимущества шаблонов проектирования:
Решения проверены временем. Поскольку паттерны проектирования часто используются многими разработчиками, вы можете быть уверены, что они работают. Плюс они неоднократно пересматривались и, возможно, уже оптимизированы.
Легко поддаются многократному использованию. Паттерны проектирования документируют многоразовое решение, которое может быть изменено для решения множества конкретных задач, поскольку они не привязаны к конкретной проблеме.
Облегчают коммуникацию. Когда разработчики знакомы с паттернами проектирования, им легче общаться друг с другом по поводу потенциальных решений той или иной проблемы.
Нет необходимости рефакторинга кода. Если приложение написано с учетом паттернов проектирования, часто бывает так, что в дальнейшем вам не придется рефакторить код, потому что применение правильного паттерна проектирования к конкретной задаче уже является оптимальным решением.
Уменьшают размер кодовой базы. Поскольку паттерны проектирования обычно представляют собой элегантные и оптимальные решения, они обычно требуют меньше кода, чем другие решения.
Краткая история JavaScript
JavaScript - один из самых популярных на сегодняшний день языков программирования для веб-разработки. Изначально он был создан как своего рода «клей» для различных отображаемых HTML-элементов, известный как язык сценариев на стороне клиента, для одного из первых веб-браузеров. Он назывался Netscape Navigator и в то время мог отображать только статический HTML. Как вы уже догадались, идея создания такого языка сценариев привела к войне за браузер между крупными игроками в индустрии разработки браузеров, такими как Netscape Communications (сегодня Mozilla), Microsoft и другими.
Каждый из крупных игроков хотел продвинуть свою собственную реализацию этого языка сценариев, поэтому Netscape создал JavaScript (на самом деле это сделал Брендан Эйх), Microsoft - JScript и так далее. Как вы понимаете, различия между этими реализациями были очень велики, поэтому разработка для веб-браузеров велась для каждого браузера, с использованием стикеров, которые прилагались к веб-странице. Вскоре стало ясно, что нам нужен стандарт, кроссбраузерное решение, которое унифицировало бы процесс разработки и упростило создание веб-страниц. То, что они придумали, называется ECMAScript.
ECMAScript - это стандартизированная спецификация языка сценариев, которую стараются поддерживать все современные браузеры. Существует множество реализаций (можно сказать, диалектов) ECMAScript. Самый популярный из них - JavaScript, о котором пойдет речь в этой статье. С момента своего появления ECMAScript стандартизировал множество важных вещей, и для тех, кто интересуется конкретикой, в Википедии есть подробный список стандартизированных вещей для каждой версии ECMAScript. Поддержка браузерами ECMAScript версии 6 (ES6) и выше все еще не завершена и для полноценной поддержки должна быть транспилирована в ES5.
Что такое JavaScript?
JavaScript - это легкий, интерпретируемый, объектно-ориентированный язык программирования с первоклассными функциями, наиболее известный как язык сценариев для веб-страниц.
Вышеупомянутое определение означает, что код JavaScript занимает мало памяти, прост в реализации и легко изучается, а его синтаксис схож с такими популярными языками, как C++ и Java. Это скриптовый язык, что означает, что его код интерпретируется, а не компилируется. Он поддерживает процедурный, объектно-ориентированный и функциональный стили программирования, что делает его очень гибким для разработчиков.
Итак, мы рассмотрели все характеристики, которые похожи на многие другие языки, поэтому давайте посмотрим, что особенного есть в JavaScript по сравнению с другими языками. Я перечислю несколько характеристик и постараюсь объяснить, почему они заслуживают особого внимания.
JavaScript поддерживает функции как объекты первого класса
Это означает, что вы можете передавать функции в качестве параметров другим функциям точно так же, как и любую другую переменную. Этот код складывает два числа, а затем передает результат в колбэк-функцию, которая выводит его в консоль.
JavaScript основан на прототипах
Как и во многих других объектно-ориентированных языках, JavaScript поддерживает объекты, и одно из первых понятий, которое приходит на ум при работе с объектами, — это классы и наследование. Здесь возникает некоторая сложность, так как язык не поддерживает классы в своей базовой форме, а использует то, что называется прототипным или экземплярным наследованием.
Только в ES6 был введен формальный термин "класс", что означает, что браузеры еще не полностью поддерживают его (если помните, на момент написания последняя полностью поддерживаемая версия ECMAScript — 5.1). Важно отметить, что, даже несмотря на то, что термин "класс" введен в JavaScript, под капотом он все равно использует прототипное наследование.
Прототипное программирование — это стиль объектно-ориентированного программирования, в котором повторное использование поведения (известное как наследование) осуществляется через процесс повторного использования существующих объектов посредством делегаций, которые служат прототипами. Мы подробнее рассмотрим это, когда перейдем к разделу о шаблонах проектирования, так как эта особенность используется во многих шаблонах проектирования в JavaScript.
Циклы событий JavaScript
Если у вас есть опыт работы с JavaScript, вы наверняка знакомы с термином «функция обратного вызова». Для тех, кто не знаком с этим термином, функция обратного вызова - это функция, передаваемая в качестве параметра (помните, что JavaScript рассматривает функции как граждан первого класса) другой функции и выполняемая после наступления события. Обычно она используется для подписки на такие события, как щелчок мыши или нажатие кнопки клавиатуры.
Каждый раз, когда происходит событие, к которому привязан обработчик (иначе событие теряется), сообщение отправляется в очередь сообщений, которые обрабатываются синхронно в порядке FIFO (первым пришел — первым обработан). Это называется циклом событий (event loop).
Каждое сообщение в очереди связано с определенной функцией. Когда сообщение извлекается из очереди, среда выполнения полностью выполняет функцию, прежде чем обработать следующее сообщение. Это означает, что если функция вызывает другие функции, они все будут выполнены до того, как будет обработано новое сообщение из очереди. Это называется выполнением до завершения (run-to-completion).
queue.waitForMessage() синхронно ожидает новые сообщения. Каждое обрабатываемое сообщение имеет свой собственный стек и обрабатывается до тех пор, пока стек не опустеет. Когда выполнение завершено, из очереди берется новое сообщение, если оно есть.
Вы, возможно, слышали, что JavaScript является неблокирующим, что означает, что когда выполняется асинхронная операция, программа способна обрабатывать другие задачи, например, принимать ввод от пользователя, ожидая завершения асинхронной операции, не блокируя основной поток выполнения. Это очень полезное свойство JavaScript, и можно было бы написать целую статью только на эту тему; однако это выходит за рамки данного материала.
Что такое паттерн проектирования в JavaScript?
Как я уже говорил, паттерны проектирования - это многократно используемые решения часто встречающихся проблем при проектировании программного обеспечения. Давайте рассмотрим некоторые категории паттернов проектирования.
Прото-паттерн
Как создается паттерн? Допустим, вы распознали часто встречающуюся проблему, и у вас есть собственное уникальное решение этой проблемы, которое не признано и не задокументировано во всем мире. Вы используете это решение каждый раз, когда сталкиваетесь с этой проблемой, и считаете, что его можно использовать повторно и что сообщество разработчиков может извлечь из него пользу.
Станет ли оно сразу же шаблоном? К счастью, нет. Часто бывает так, что человек имеет хорошую практику написания кода и просто принимает что-то, что выглядит как паттерн, за паттерн, когда на самом деле это не паттерн.
Как узнать, что то, что вы думаете, что узнали, на самом деле является шаблоном?
Узнав мнение других разработчиков об этом, ознакомившись с процессом создания паттерна и хорошо изучив существующие паттерны. Существует этап, через который должен пройти паттерн, прежде чем он станет полноценным, и называется он прото-паттерн.
Прото-паттерн является будущим паттерном, если он проходит определенный период тестирования различными разработчиками и сценариями, в которых паттерн оказывается полезным и дает правильные результаты. Для того чтобы полноценный паттерн был признан сообществом, необходимо проделать довольно большой объем работы и документирования - большая часть которого выходит за рамки этой статьи.
Антипаттерн
Как паттерн проектирования представляет собой хорошую практику, так и антипаттерн представляет собой плохую практику.
Примером антипаттерна может служить модификация прототипа класса Object. Почти все объекты в JavaScript наследуются от Object (помните, что JavaScript использует наследование по прототипу), поэтому представьте себе сценарий, в котором вы изменили этот прототип. Изменения прототипа Object будут видны во всех объектах, которые наследуют от этого прототипа - а это большинство объектов JavaScript. Это катастрофа, которая только и ждет, чтобы произойти.
Другой пример, похожий на упомянутый выше, - изменение объектов, которые вам не принадлежат. Примером может служить переопределение функции объекта, используемого во многих сценариях в приложении. Если вы работаете с большой командой, представьте, какую путаницу это вызовет; вы быстро столкнетесь с коллизиями в наименованиях, несовместимыми реализациями и кошмарами обслуживания.
Подобно тому, как полезно знать обо всех хороших практиках и решениях, очень важно знать и о плохих. Таким образом, вы сможете распознать их и избежать ошибок.
Категоризация паттернов проектирования
Шаблоны дизайна можно классифицировать множеством способов, но наиболее популярными являются следующие:
Творческие паттерны проектирования
Структурные паттерны проектирования
Поведенческие шаблоны проектирования
Конкурентоспособные шаблоны проектирования
Архитектурные шаблоны проектирования
Паттерны креативного проектирования
Эти паттерны касаются механизмов создания объектов, которые оптимизируют создание объектов по сравнению с базовым подходом. Базовая форма создания объектов может привести к проблемам в проектировании или к увеличению сложности проекта. Паттерны креативного проектирования решают эту проблему, каким-то образом управляя созданием объектов. Некоторые из популярных паттернов проектирования в этой категории:
Метод фабрики
Абстрактная фабрика
Конструктор
Прототип
Синглтон
Структурные паттерны проектирования
Эти паттерны связаны с отношениями между объектами. Они гарантируют, что при изменении одной части системы, вся система не должна меняться вместе с ней. Наиболее популярными паттернами в этой категории являются:
Адаптер
Мост
Композит
Декоратор
Фасад
Flyweight
Прокси
Поведенческие паттерны проектирования
Эти шаблоны распознают, реализуют и улучшают связь между разрозненными объектами в системе. Они помогают обеспечить синхронизацию информации между разрозненными частями системы. Популярными примерами таких паттернов являются:
Цепочка ответственности
Команда
Итератор
Посредник
Memento
Наблюдатель
Состояние
Стратегия
Посетитель
Конкурентоспособные шаблоны проектирования
Эти типы паттернов проектирования связаны с парадигмами многопоточного программирования. Некоторые из них популярны:
Активный объект
Ядерная реакция
Планировщик
Архитектурные шаблоны проектирования
Шаблоны проектирования, которые используются в архитектурных целях. К наиболее известным из них относятся:
MVC (Model-View-Controller)
MVP (Model-View-Presenter)
MVVM (Model-View-ViewModel).
В следующем разделе мы подробно рассмотрим некоторые из вышеупомянутых паттернов проектирования с примерами для лучшего понимания.
Примеры шаблонов проектирования
Каждый из паттернов проектирования представляет собой определенный тип решения конкретной проблемы. Не существует универсального набора паттернов, который бы всегда подходил лучше всего. Нам нужно узнать, когда тот или иной паттерн окажется полезным и принесет ли он реальную пользу. Как только мы познакомимся с паттернами и сценариями, для которых они лучше всего подходят, мы сможем легко определить, подходит ли конкретный паттерн для решения конкретной проблемы.
Помните, что применение неправильного паттерна для решения конкретной задачи может привести к таким нежелательным последствиям, как излишнее усложнение кода, ненужное влияние на производительность или даже порождение нового антипаттерна.
Все это важно учитывать, когда вы думаете о применении паттерна проектирования в нашем коде. Мы рассмотрим некоторые паттерны проектирования в JS, с которыми должен быть знаком каждый опытный разработчик JavaScript.
Шаблон конструктора
Когда речь идет о классических объектно-ориентированных языках, конструктор — это специальная функция в классе, которая инициализирует объект с набором значений по умолчанию и/или переданными значениями.
Обычно в JavaScript объекты создаются следующими тремя способами:
После создания объекта существует четыре способа (начиная с ES3) добавить свойства в эти объекты. Вот они:
Наиболее популярный способ создания объектов — это использование фигурных скобок, а для добавления свойств — точечная нотация или квадратные скобки. Любой, кто имеет опыт работы с JavaScript, использовал их.
Мы ранее упоминали, что JavaScript не поддерживает нативные классы, но поддерживает конструкторы через использование ключевого слова new, добавляемого перед вызовом функции. Таким образом, мы можем использовать функцию в качестве конструктора и инициализировать её свойства так же, как мы это делаем в классических языках.
Однако здесь есть пространство для улучшений. Как я уже упоминал ранее, JavaScript использует наследование на основе прототипов. Проблема с предыдущим подходом заключается в том, что метод writesCode переопределяется для каждого экземпляра конструктора Person. Мы можем избежать этого, задав метод в прототип функции:
Теперь оба экземпляра конструктора Person могут получить доступ к общей версии метода writesCode().
Модульный паттерн
Что касается особенностей JavaScript, он никогда не перестаёт удивлять. Ещё одна интересная особенность JavaScript (по крайней мере, с точки зрения объектно-ориентированных языков) заключается в том, что JavaScript не поддерживает модификаторы доступа. В классическом объектно-ориентированном языке пользователь определяет класс и задаёт права доступа для его членов. Поскольку в JavaScript в его обычной форме отсутствуют как классы, так и модификаторы доступа, разработчики JavaScript придумали способ имитировать это поведение при необходимости.
Прежде чем углубиться в специфику модульного паттерна, давайте обсудим концепцию замыкания. Замыкание — это функция, которая имеет доступ к области видимости родительской функции, даже после её завершения. Замыкания помогают нам имитировать поведение модификаторов доступа через области видимости. Покажем это на примере:
Как видите, с помощью IIFE (немедленно вызываемого функционального выражения) мы привязали переменную counter к функции, которая была вызвана и завершилась, но по-прежнему доступна дочерней функции, которая её увеличивает. Так как мы не можем получить доступ к переменной counter извне функционального выражения, мы сделали её приватной через манипуляцию с областью видимости.
Используя замыкания, мы можем создавать объекты с приватными и публичными частями. Эти объекты называются модулями и очень полезны, когда мы хотим скрыть некоторые части объекта и открыть только интерфейс для его использования. Покажем это на примере:
Самое полезное, что вводит этот паттерн, — это чёткое разделение приватных и публичных частей объекта, что очень похоже на концепцию для разработчиков с классическим объектно-ориентированным опытом.
Однако, не всё так идеально. Если вы захотите изменить видимость какого-либо члена, вам придётся модифицировать код везде, где вы использовали этот член, из-за различий в способах доступа к публичным и приватным частям. Кроме того, методы, добавленные к объекту после его создания, не могут получить доступ к приватным членам объекта.
Раскрывающий модульный шаблон
Этот шаблон является улучшением модульного шаблона, как показано выше. Главное отличие состоит в том, что вся логика объекта пишется в приватной области модуля, а затем мы просто открываем те части, которые хотим сделать публичными, возвращая анонимный объект. Также можно изменить имена приватных членов при их сопоставлении с публичными членами.
Раскрывающий модульный шаблон — это один из как минимум трёх способов реализации модульного шаблона. Основные различия между раскрывающим модульным шаблоном и другими вариантами заключаются в том, как ссылаются на публичные члены. В результате раскрывающий модульный шаблон легче использовать и изменять, однако он может быть хрупким в определённых сценариях, таких как использование объектов RMP в качестве прототипов в цепочке наследования. Проблемные ситуации следующие:
Если у нас есть приватная функция, которая ссылается на публичную функцию, мы не можем переопределить публичную функцию, так как приватная функция будет продолжать ссылаться на приватную реализацию, что может привести к ошибке в системе.
Если публичный член ссылается на приватную переменную, и мы пытаемся переопределить публичный член извне модуля, другие функции всё равно будут ссылаться на приватное значение переменной, что также может привести к ошибке в системе.
Шаблон синглтона
Шаблон синглтона используется в сценариях, когда нам требуется ровно один экземпляр класса. Например, если нам нужен объект, содержащий конфигурацию для чего-либо. В таких случаях не обязательно создавать новый объект каждый раз, когда в системе требуется конфигурация.
Как видно из примера, случайное число генерируется один раз, так же как и переданные значения конфигурации.
Важно отметить, что точка доступа для получения значения синглтона должна быть только одна и хорошо известная. Недостатком этого шаблона является то, что его сложно тестировать.
Паттерн посредника
Мы кратко рассмотрим паттерн, который также очень полезен, когда речь идет о разрозненных системах. Когда у нас есть сценарий, в котором несколько частей системы должны взаимодействовать и быть скоординированными, возможно, хорошим решением будет внедрение посредника.
Посредник - это объект, который используется в качестве центральной точки для связи между разрозненными частями системы и управляет рабочим процессом между ними. Важно подчеркнуть, что он управляет рабочим процессом. Почему это важно?
Потому что здесь есть большое сходство с шаблоном издатель/подписчик. Вы можете спросить себя: хорошо, эти два паттерна помогают реализовать лучшую связь между объектами... В чем же разница?
Разница в том, что посредник управляет рабочим процессом, в то время как издатель/подписчик использует так называемый тип связи «отдать и забыть». Издатель/подписчик - это просто агрегатор событий, то есть он просто заботится о том, чтобы запускать события и сообщать нужным подписчикам, какие события были запущены. Агрегатор событий не заботится о том, что происходит после того, как событие было отработано, чего нельзя сказать о медиаторе.
Хорошим примером посредника является интерфейс типа wizard. Допустим, у вас есть большой процесс регистрации для системы, над которой вы работали. Часто, когда от пользователя требуется много информации, рекомендуется разбить его на несколько этапов.
Таким образом, код будет намного чище (его будет легче поддерживать), а пользователь не будет перегружен количеством информации, которая запрашивается только для того, чтобы завершить регистрацию. Посредник - это объект, который будет обрабатывать шаги регистрации, принимая во внимание различные возможные рабочие процессы, которые могут произойти из-за того, что у каждого пользователя потенциально может быть уникальный процесс регистрации.
Очевидным преимуществом этого паттерна проектирования является улучшение взаимодействия между различными частями системы, которые теперь взаимодействуют через посредника и более чистую кодовую базу.
Недостатком является то, что теперь мы ввели единую точку отказа в нашу систему, то есть если наш посредник выйдет из строя, вся система может перестать работать.
Шаблон фасада
Он используется, когда мы хотим создать абстрактный слой между тем, что представлено публично, и тем, что реализовано за кулисами. Он применяется, когда требуется более простой или удобный интерфейс для работы с подлежащим объектом.
Отличный пример этого шаблона можно найти в селекторах библиотек для манипуляции DOM, таких как jQuery, Dojo или D3. Возможно, вы замечали, что эти библиотеки обладают очень мощными функциями селектора; можно писать сложные запросы, например:
Это значительно упрощает работу с выборками, и, хотя на первый взгляд это кажется простым, за этим скрывается сложная логика, которая реализована "под капотом".
Также нужно учитывать компромисс между производительностью и простотой. Желательно избегать излишней сложности, если она не приносит достаточной пользы. В случае упомянутых библиотек этот компромисс оправдан, так как все они очень успешны.
Следующие шаги
Шаблоны проектирования — это очень полезный инструмент, который любой опытный разработчик JavaScript должен знать. Знание особенностей шаблонов проектирования может быть чрезвычайно полезным и сэкономить много времени на протяжении всего жизненного цикла проекта, особенно на этапе поддержки. Изменение и поддержка систем, разработанных с помощью шаблонов проектирования, которые хорошо подходят для нужд системы, может оказаться бесценным.
