Return intitle все публикации пользователя просмотров. Поиск слов при помощи дополнительных операторов

01.05.2019

У всех, кто впервые сталкивается с MODx Evolution, очень часто возникают подобные вопросы: как вывести дату создания документа, как вывести автора документа, как вывести заголовок родителя и т.д. и т.п. Согласитесь, не для всех это может оказаться элементарным на первых шагах изучения MODx. А сколько было потрачено нервов и времени в бесплодных попытках найти нужный ответ! И не всегда даже найденный ответ бывает очевиден и понятен. Хватит! Настало время дать сразу все ответы на все вопросы. Ну в меру собственных сил и знаний, конечно. В этой статье я буду собирать все подобные вопросы и стараться дать максимально подробный ответ, конечно же все это будет сопровождаться готовыми рабочими примерами, которые каждый сможет применить на практике.

Автор не считает себя великим гуру, поэтому, в подготовке этой статьи рассчитывает на помощь читателей. Присылайте свои вопросы и найденные решения, комментируйте и предлагайте альтернативные подходы, критикуйте и становитесь соавторами этой подборки.

Спрашивали? Отвечаем!

Сниппеты можно вызывать двумя способами:

[[НазваниеСниппета]] - кэшируемый вызов сниппета
[!НазваниеСниппета!] - некэшируемый вызов сниппета

Если вызов основного сниппета некэшируемый, то в шаблоне сниппет обязательно должен быть кэшируемым. Более того, чтобы избежать проблем с выводом сниппетов (например с постраничным разбиением), основной сниппет желательно всегда делать некэшируемым.

К примеру, имеем некэшируемый вызов Ditto :

[!Ditto? &startID=`10` &tpl=`ditto_tpl`!]

у которого в шаблоне ditto_tpl надо вызвать сниппет Wayfinder :


[`]]

Расширим задачу, сформулировав вопрос так: Как вообще выводить даты? Т.е. это может быть любая дата, как в шаблоне для Ditto так и на странице самого документа.

а) Задача: вывести дату создания документа в ленте новостей

Для вывода даты нам потребуется вставить в шаблон news_tpl в месте вывода этой даты специальный плэйсхолдер Ditto - [+date+] - он выводит дату в установленном формате (которую мы зададим позже, при вызове Ditto). По умолчанию используется значение createdon (дата создания документа). Может принимать значения: editedon (дата последнего редактирования) и pub_date (дата публикации документа).

Создаем чанк news_tpl :


[+date+] | [+longtitle+]

[+introtext+]


Для того, чтобы задать параметр из которого Ditto будет брать значение даты используем &dateSource=`editedon` . Для того чтобы задать формат даты, используем &dateFormat=`%d.%m.%Y` , где значением выступает любой валидный формат времени, который соответствует правилам функции PHP - strftime:

Символы для обозначения формата времени функции strftime
%a сокращенное название дня недели в текущей локали Пн
%A полное название дня недели в текущей локали 18.03.2019
%b сокращенное название месяца недели в текущей локали 18.03.2019
%B полное название месяца недели в текущей локали Март
%c предпочтительный формат даты и времени в текущей локали 18.03.2019
%C столетие (год, деленный на 100 и огругленный до целого, от 00 до 99) 18.03.2019
%d день месяца в виде десятичного числа (от 01 до 31) 18.03.2019
%D аналогично %m/%d/%y 18.03.2019
%e день месяца в виде десятичного числа, если это одна цифра, то перед ней добавляется пробел (от " 1" до "31") 18.03.2019
%g подобно %G, но без столетия. 18.03.2019
%G Год, 4-значное число, соответствующее номеру недели по ISO (см. %V). Аналогично %Y, за исключением того, что если номер недели по ISO соответствует предыдущему или следующему году, используется соответствующий год. 2019
%h аналогично %b мар
%H номер часа от 00 до 23 18.03.2019
%I номер часа от 01 до 12 18.03.2019
%j номер дня в году (от 001 до 366) 077
%m номер месяца (от 01 до 12) 18.03.2019
%M минуты 18.03.2019
%n символ "\n" 18.03.2019
%p `am" или `pm", или соответствующие строки в текущей локали 18.03.2019
%r время в формате a.m. или p.m. 18.03.2019
%R время в 24-часовом формате 18.03.2019
%S секунды 18.03.2019
%t символ табуляции ("\t") 18.03.2019
%T текущее время, аналогично %H:%M:%S 18.03.2019
%u номер дня недели от 1 до 7, где 1 соответствует понедельнику 18.03.2019
%U порядковый номер недели в текущем году. Первым днем первой недели в году считается первое воскресенье года. 18.03.2019
%V Порядковый номер недели в году по стандарту ISO 8601:1988 от 01 до 53, где 1 соответствует первой неделе в году, в которой как минимум 4 дня принадлежат этому году. Первым днем недели считается понедельник. (Используйте %G or %g для определения соответствующего года) 12
%W порядковый номер недели в текущем году. Первым днем первой недели в году считается первый понедельник года. 18.03.2019
%w номер дня недели, 0 соответствует воскресенью 18.03.2019
%x предпочтительный формат даты без времени в текущей локали 18.03.2019
%X предпочтительный формат времени без даты в текущей локали 18.03.2019
%y год без столетия (от 00 до 99) 18.03.2019
%Y год, включая столетие 18.03.2019
%Z временная зона в виде смещения, аббривеатуры или полного наименования 18.03.2019
%% символ `%" 18.03.2019

Примеры вызова Ditto с разными значениями даты:

[!Ditto? &startID=`10` &tpl=`news_tpl` &dateSource=`createdon` &dateFormat=`%d.%m.%Y` &display=`5`!] // дата создания документа
[!Ditto? &startID=`10` &tpl=`news_tpl` &dateSource=`editedon` &dateFormat=`%d.%m.%Y` &display=`5`!] // дата последного редактирования документа
[!Ditto? &startID=`10` &tpl=`news_tpl` &dateSource=`pub_date` &dateFormat=`%d.%m.%Y` &display=`5`!] // дата публикации документа

б) Задача: вывести дату на странице самой новости

Казалось бы, чего проще? Меняем в чанке news_tpl все + на * и нужный чанк готов. Но в MODx нет специального тега [*date*], поэтому, вместо него придется использовать [*createdon*] , [*editedon*] или [*pub_date*] .

Для начала пробуем [*createdon*] или [*editedon*] и получаем вместо даты что-то типа этого:

1318407717

Почему же так получилось? Потому что, любое время в БД записывается в виде Unix Timestamp — количество секунд от 1 января 1970 года до текущего момента. Зачем же такое придумали? Ну, например, для того, чтобы была возможность оперировать датой в независимости от ее формата. На самом деле, это будет легко перевести в нужный нам формат, но об этом чуть позже.

Берем следующий параметр [*pub_date*] и получаем:

Ну а тут то что не так, спросите вы? Оказывается, по-умолчанию параметр pub_date не устанавливается, поэтому его значение равно 0 и попытка его вывести выдаст 0 или 01.01.1970. Чтобы избежать этого, придется параметр pub_date делать обязательным к заполнению или установить ему значение по умолчанию. В этом нам поможет ManagerManager . Но даже если параметр будет заполнен, на выходе мы вновь увидим количество секунд, прошедших с 01.01.1970.

Решение 1. На помощь придет PHx , только прежде чем его устанавливать, ознакомьтесь с возможными проблемами. При установленном PHx вывод даты можно сделать таким образом:

[*createdon:date=`%d.%m.%Y`*] // дата создания документа
[*editedon:date=`%d.%m.%Y`*] // дата последнего редактирования документа
[*pub_date:date=`%d.%m.%Y`*] // дата публикации документа

Кстати, PHx можно использовать и в шаблоне Ditto, вставив вместо плэйсхолдера [+date+] один из этих плэйсхолдеров:

[+createdon:date=`%d.%m.%Y`+] // дата создания документа
[+editedon:date=`%d.%m.%Y`+] // дата последнего редактирования документа
[+pub_date:date=`%d.%m.%Y`+] // дата публикации документа

В этом слачае, при вызове Ditto параметры &dateSource и &dateFormat не нужны.

Решение 2. Для вывода даты в нужном формате можно воспользоваться сниппетом. Создаем новый сниппет, назовем его, к примеру, DateFormat , и помещаем в него следующий код:

setlocale(LC_ALL, "ru_RU.UTF-8");

if ($val == "") $val=time();
if ($format == "") $format = "%d.%m.%Y";
return strftime($format, $val);
?>

В том месте, где нам необходимо вывести дату, помещаем такой вызов этого сниппета:

[!DateFormat? &val=`[*createdon*]` &format=`%d.%m.%Y`!]

В параметре &val мы задаем значение для даты, а в параметре &format нужный формат. Сниппет может применяться как на странице новости, так и в шаблоне для Dito, не забудьте, если Ditto вызывается некэшируемым, то в его шаблоне сниппет должен вызываться как кэшируемый.

Если вызвать сниппет вообще без параметров:

[!DateFormat!]

то он выведет текущую дату в формате заданном по умолчанию: "%d.%m.%Y", этот формат можно поменять в коде сниппета.

Вот пример, где это может пригодиться: Необходимо отсортировать горящие туры по дате вылета. Дата вылета задается в TV-параметре data_toura с типом ввода Date. При этом, эта дата должна быть выведена в ленте горящих туров и на странице самого тура в формате %d-%m-%Y.

Для того, чтобы можно было отсортировать туры в ленте горящих туров, которая выводится с помощью снипета Ditto, мы будем использовать параметр &orderBy=`data_toura ASC` . Для того, чтобы сортировка у нас получилась правильная, необходимо задать параметру data_toura значение в формате количества секунд, прошедших с 1 января 1970 года. Для этого нам необходимо установить у этого параметра значение Визуальный компонент как Unixtime :

Для отображения этой даты в шаблоне Ditto и на странице тура будем использовать PHx или сниппет DateFormat из предыдущей статьи:

[!DateFormat? &val=`[*data_toura*]` &format=`%d-%m-%Y`!] // на странице тура
[` &format=`%d-%m-%Y`]] // в шаблоне Ditto

Создаём сниппет convertDate и вставляем в него такой код:

$MyDate= (isset($MyDate)) ? $MyDate: $modx -> documentObject["MyDate"];
$type= (isset($type)) ? $type: $modx -> documentObject["type"];
$monthes = array("","января","февраля","марта","апреля","мая","июня","июля","августа","сентября","октября","ноября","декабря");
$day = date("j" ,$MyDate);
$month = $monthes;
$year = date("Y",$MyDate);

echo $day." ".$month." ".$year." года";
?>

Вызываем сниппет:

[!convertDate? &MyDate=`[*createdon*]`!] // в документе MODx
[`]] // в шаблоне Ditto

В качестве значения параметра &MyDate могут выступать createdon, editedon, pub_date, unpub_date и TV-параметр с типом ввода Date и визуальным компонентом Unixtime .

Решение 1. Для этой цели можно воспользоваться возможностями PHx , если он у вас установлен.

Логин того, кто создал документ, будет выводиться таким образом:

[*createdby:userinfo=`username`*] // в докуенте MODx
[+createdby:userinfo=`username`+] // в шаблоне Ditto

К примеру, если документ создал администратор, то выведется его логин admin.

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

[*createdby:userinfo=`fullname`*]

В этом случае выведется Default admin account - это значение полного имени администратора по умолчанию. Чтобы вывелось Администратор или как-то иначе, необходимо заменить его полное имя в Пользователи >> Управление менеджерами .

Для вывода E-mail пользователя:

[*createdby:userinfo=`email`*]

Решение 2. Плагин PHx можно заменить простым сниппетом. Создадим новый сниппет UserInfo с таким кодом:

/*
* UserInfo - сниппет для получения данных пользователя
*/
$output = "";
$userinfo = $modx->getUserInfo($id); //Используем Id пользователя для получения массива с данными пользователя
$out1 = $userinfo["fullname"]; // Получаем полное имя пользователя
$out2 = $userinfo["phone"]; // Получаем телефон пользователя
$out3 = $userinfo["email"]; // Получаем электронный адрес пользователя
$output = "Автор: " . $out1 . " Телефон: " . $out2 . " E-mail: " . $out3;
return $output;
?>

В шаблоне помещаем такой вызов сниппета:

[!UserInfo? &id=`[*createdby*]`!]

&id=`[*createdby*]` - передаем в наш сниппет ID пользователя, создавшего документ. С помощью параметра editedby можно передать ID пользователя, редактировавшего документ.

С помощью этого сниппета можно выводить любые данные пользователя из таблицы user_attributes. Описание getUserInfo .

Решение 1. Вновь расширим задачу: Как вообще выводить параметры родительского документа?

Вывести ID родительского документа мы можем с помощью специального тега MODx:

[*parent*] // в документе MODx
[+parent+] // а шаблоне Ditto

Чтобы вывести заголовок родительского документа, применяем PHx:

[*id:parent=`pagetitle`*] // в документе MODx
[+id:parent=`pagetitle`+] // а шаблоне Ditto

Чтобы вывести ID родителя родителя, т.е. дедушки:

[*parent:parent=`id`*] // в документе MODx
[+parent:parent=`id`+] // а шаблоне Ditto

Чтобы вывести заголовок прадедушки:

[*parent:parent=`id`:parent=`pagetitle`*] // в документе MODx
[+parent:parent=`id`:parent=`pagetitle`+] // а шаблоне Ditto

[*parent:parent=`id`:parent=`id`:parent=`pagetitle`*] // в документе MODx
[+parent:parent=`id`:parent=`id`:parent=`pagetitle`+] // а шаблоне Ditto

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

[*id:parent=`longtitle`*] // в документе MODx
[+id:parent=`longtitle`+] // а шаблоне Ditto

Решение 2. Если по каким-то причинам вы не можете использовать PHx, на помощь придет сниппет getField .

Скачайте и установите сниппет, как это описано в документации . Чтобы получить заголовок родительского документа, сниппет надо вызвать с такими параметрами:

[!GetField? &parent=`0` &field=`pagetitle`!]

При parent=0 будет использоваться родительский документ. В качестве значения параметра field можно указывать любое поле документа или TV-параметр.

Чтобы получить заголовок или другое поле "дедушки", используются следующие параметры:

[!GetField? &parent=`1` &parentLevel=`2` &field=`pagetitle`!]

При parent=1 используется корневой каталог. Параметр parentLevel определяет глубину вложенности от текущего документа до корневого каталога: 0 - корневой документ, 1 - родитель, 2 - дедушка, 3 - прадедушка и т.д.

Этот сниппет позволяет выводить любой параметр любого документа. С помощью параметра docid можно задать ID интересующего документа, а с помощью параметра field необходимое поле или TV-параметр:

[!GetField? &docid=`25` &field=`pagetitle`!]

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

Для этих целей используем сниппет truncate . Код сниппета:

$lenf = $len;

//Заменяет символы перевода строки на HTML тег
$order = array("\r\n", "\n", "\r");
$replace = "
";
$what = str_replace($order, $replace, $text);

if (strlen($what) > $lenf) {
$what = preg_replace("/^(.{" . $lenf . ",}?).*$/is", "$1", $what) . "...";
}
return $what;
?>

Вызов сниппета будет таким:

[!truncate? &text=[*pagetitle*] &len=200!] // в документе MODx
[ &len=200]] // а шаблоне Ditto

Сниппет обрежет текст до определенного количества символов не обрезая слова и добавит в конце три точки.

Придется отредактировать файл assets/snippets/ditto/formats/rss.format.inc.php
На 80 строчке есть такая запись:

$GLOBALS["dateSource"] = isset($dateSource) ? $dateSource: "createdon";
// date type to display (values can be createdon, pub_date, editedon)

// set tpl rss placeholders
$placeholders["rss_date"] = array($GLOBALS["dateSource"],"rss_date");

Т.е. по умолчанию используется createdon . Надо заменить на pub_date , т.е.:

$GLOBALS["dateSource"] = isset($dateSource) ? $dateSource: "pub_date";

Если у вас псевдонимы генерируются автоматически с помощью плагина TransAlias, то такие знаки препинания, как "!", ":", "," и т.д. автоматически появятся и в вашем псевдониме, если они присутствуют в заголовке. Но если запятая или восклицательный знак не влияют на работоспособность псевдонима, тем не менее, их присутствие вряд ли его украсит. К счастью, это легко исправляется.

В настройках TransAlias достаточно выбрать в параметре Restrict alias to значение lowercase alphanumeric и псевдонимы будут генерироваться правильно, т.е. без лишних знаков препинания.

Для этого воспользуемся сниппетом ChildCounter (сниппет найден ):

$docid = isset($docid) ? intval($docid) : $modx->documentIdentifier;
$depth = isset($depth) ? intval($depth) : 0;
$isfolder = isset($isfolder) ? intval($isfolder): 0;
$tpl = isset($tpl) ? $tpl: -1;
$published = isset($published) ? intval($published): 1;
$davailable = $modx->getChildIds($docid, $depth);

if ($davailable){
$where = ($tpl > 0) ? "template=".$tpl: "isfolder=".$isfolder;
$dcount = $modx->getDocuments($davailable, $published, 0, "id", $where);
return count($dcount);
}
return 0;
?>

Параметры сниппета ChildCounter :

&dicId - ID сканируемой папки

&depth - глубина сканирования
&isfolder - Если 1 - вернёт количество папок, если 0 - количество документов НЕ папок. Значения 0 или 1. По умолчанию 0.
&published - Если 0 - вернёт количество неопубликованных документов, если 1 - количество опубликованных документов. Значения 0 или 1. По умолчанию 1.

&tpl - если указан, то возвращает количество документов с шаблоном id которого равен &tpl

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

[]

AlterTitle выводит pagetitle если не заполнен longtitle .

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

[`]]

&id=`[*id*]` - передаем в сниппет ID ресурса, в котором вызываем сниппет. Фактически, этот сниппет можно использовать и для вывода заголовка родителя, передав [*parent*].

Пример 2.

Аналогичную конструкцию можем применять и для других параметров. Например, у нас есть параметр foto у шаблона Новости , в котором содержится картинка для новостей, но не у всех новостей будут картинки. И если у новости нет картинки, нам необходимо вывести картинку "заглушку". Я поступил следующим образом, создал еще один параметр nofoto тип ввода Image и назначил его шаблону Новости . В значении по умолчанию указал путь к картинке "заглушке". С помощью плагина ManagerManager спрятал этот параметр от всех пользователей:

Mm_hideFields("nofoto"); где

&directOutput=`1` - выводим результат работы сниппета напрямую, без использования плэйсхолдеров

После встречи очередного нового года и длинных и запойных выходных, вы возвращаетесь к работе и обнаруживаете, что у всех ваших сайтов надо обновлять год в копирайте. А почему бы не автоматизировать сей процесс? Подобная идея уже приходила в голову не только мне, поэтому я довольно быстро нашел готовое решение в пару строчек и немного его модифицировал.

Создайте новый сниппет (название не так важно, ну пусть будет copyright ) с таким кодом:

$copyfrom = (isset($copyfrom)) ? $copyfrom: "2012";
$copyholder = (isset($copyholder)) ? $copyholder: " [(site_name)]";
if (date("Y") != $copyfrom) { $copytill = " - " . date("Y"); }
$copyright = " " . $copyfrom . $copytill . $copyholder;
return $copyright;
?>

Пример вызова:

[]

[]

©holder=`Иван Иванович Иванов.` - обладатель авторских прав. По умолчанию - название сайта.

Получение частных данных не всегда означает взлом - иногда они опубликованы в общем доступе. Знание настроек Google и немного смекалки позволят найти массу интересного - от номеров кредиток до документов ФБР.

WARNING

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

К интернету сегодня подключают всё подряд, мало заботясь об ограничении доступа. Поэтому многие приватные данные становятся добычей поисковиков. Роботы-«пауки» уже не ограничиваются веб-страницами, а индексируют весь доступный в Сети контент и постоянно добавляют в свои базы не предназначенную для разглашения информацию. Узнать эти секреты просто - нужно лишь знать, как именно спросить о них.

Ищем файлы

В умелых руках Google быстро найдет все, что плохо лежит в Сети, - например, личную информацию и файлы для служебного использования. Их частенько прячут, как ключ под половиком: настоящих ограничений доступа нет, данные просто лежат на задворках сайта, куда не ведут ссылки. Стандартный веб-интерфейс Google предоставляет лишь базовые настройки расширенного поиска, но даже их будет достаточно.

Ограничить поиск по файлам определенного вида в Google можно с помощью двух операторов: filetype и ext . Первый задает формат, который поисковик определил по заголовку файла, второй - расширение файла, независимо от его внутреннего содержимого. При поиске в обоих случаях нужно указывать лишь расширение. Изначально оператор ext было удобно использовать в тех случаях, когда специфические признаки формата у файла отсутствовали (например, для поиска конфигурационных файлов ini и cfg, внутри которых может быть все что угодно). Сейчас алгоритмы Google изменились, и видимой разницы между операторами нет - результаты в большинстве случаев выходят одинаковые.


Фильтруем выдачу

По умолчанию слова и вообще любые введенные символы Google ищет по всем файлам на проиндексированных страницах. Ограничить область поиска можно по домену верхнего уровня, конкретному сайту или по месту расположения искомой последовательности в самих файлах. Для первых двух вариантов используется оператор site, после которого вводится имя домена или выбранного сайта. В третьем случае целый набор операторов позволяет искать информацию в служебных полях и метаданных. Например, allinurl отыщет заданное в теле самих ссылок, allinanchor - в тексте, снабженном тегом , allintitle - в заголовках страниц, allintext - в теле страниц.

Для каждого оператора есть облегченная версия с более коротким названием (без приставки all). Разница в том, что allinurl отыщет ссылки со всеми словами, а inurl - только с первым из них. Второе и последующие слова из запроса могут встречаться на веб-страницах где угодно. Оператор inurl тоже имеет отличия от другого схожего по смыслу - site . Первый также позволяет находить любую последовательность символов в ссылке на искомый документ (например, /cgi-bin/), что широко используется для поиска компонентов с известными уязвимостями.

Попробуем на практике. Берем фильтр allintext и делаем так, чтобы запрос выдал список номеров и проверочных кодов кредиток, срок действия которых истечет только через два года (или когда их владельцам надоест кормить всех подряд).

Allintext: card number expiration date /2017 cvv

Когда читаешь в новостях, что юный хакер «взломал серверы» Пентагона или NASA, украв секретные сведения, то в большинстве случаев речь идет именно о такой элементарной технике использования Google. Предположим, нас интересует список сотрудников NASA и их контактные данные. Наверняка такой перечень есть в электронном виде. Для удобства или по недосмотру он может лежать и на самом сайте организации. Логично, что в этом случае на него не будет ссылок, поскольку предназначен он для внутреннего использования. Какие слова могут быть в таком файле? Как минимум - поле «адрес». Проверить все эти предположения проще простого.


Inurl:nasa.gov filetype:xlsx "address"


Пользуемся бюрократией

Подобные находки - приятная мелочь. По-настоящему же солидный улов обеспечивает более детальное знание операторов Google для веб-мастеров, самой Сети и особенностей структуры искомого. Зная детали, можно легко отфильтровать выдачу и уточнить свойства нужных файлов, чтобы в остатке получить действительно ценные данные. Забавно, что здесь на помощь приходит бюрократия. Она плодит типовые формулировки, по которым удобно искать случайно просочившиеся в Сеть секретные сведения.

Например, обязательный в канцелярии министерства обороны США штамп Distribution statement означает стандартизированные ограничения на распространение документа. Литерой A отмечаются публичные релизы, в которых нет ничего секретного; B - предназначенные только для внутреннего использования, C - строго конфиденциальные и так далее до F. Отдельно стоит литера X, которой отмечены особо ценные сведения, представляющие государственную тайну высшего уровня. Пускай такие документы ищут те, кому это положено делать по долгу службы, а мы ограничимся файлами с литерой С. Согласно директиве DoDI 5230.24, такая маркировка присваивается документам, содержащим описание критически важных технологий, попадающих под экспортный контроль. Обнаружить столь тщательно охраняемые сведения можно на сайтах в домене верхнего уровня.mil, выделенного для армии США.

"DISTRIBUTION STATEMENT C" inurl:navy.mil

Очень удобно, что в домене.mil собраны только сайты из ведомства МО США и его контрактных организаций. Поисковая выдача с ограничением по домену получается исключительно чистой, а заголовки - говорящими сами за себя. Искать подобным образом российские секреты практически бесполезно: в доменах.ru и.рф царит хаос, да и названия многих систем вооружения звучат как ботанические (ПП «Кипарис», САУ «Акация») или вовсе сказочные (ТОС «Буратино»).


Внимательно изучив любой документ с сайта в домене.mil, можно увидеть и другие маркеры для уточнения поиска. Например, отсылку к экспортным ограничениям «Sec 2751», по которой также удобно искать интересную техническую информацию. Время от времени ее изымают с официальных сайтов, где она однажды засветилась, поэтому, если в поисковой выдаче не удается перейти по интересной ссылке, воспользуйся кешем Гугла (оператор cache) или сайтом Internet Archive.

Забираемся в облака

Помимо случайно рассекреченных документов правительственных ведомств, в кеше Гугла временами всплывают ссылки на личные файлы из Dropbox и других сервисов хранения данных, которые создают «приватные» ссылки на публично опубликованные данные. С альтернативными и самодельными сервисами еще хуже. Например, следующий запрос находит данные всех клиентов Verizon, у которых на роутере установлен и активно используется FTP-сервер.

Allinurl:ftp:// verizon.net

Таких умников сейчас нашлось больше сорока тысяч, а весной 2015-го их было на порядок больше. Вместо Verizon.net можно подставить имя любого известного провайдера, и чем он будет известнее, тем крупнее может быть улов. Через встроенный FTP-сервер видно файлы на подключенном к маршрутизатору внешнем накопителе. Обычно это NAS для удаленной работы, персональное облако или какая-нибудь пиринговая качалка файлов. Все содержимое таких носителей оказывается проиндексировано Google и другими поисковиками, поэтому получить доступ к хранящимся на внешних дисках файлам можно по прямой ссылке.

Подсматриваем конфиги

До повальной миграции в облака в качестве удаленных хранилищ рулили простые FTP-серверы, в которых тоже хватало уязвимостей. Многие из них актуальны до сих пор. Например, у популярной программы WS_FTP Professional данные о конфигурации, пользовательских аккаунтах и паролях хранятся в файле ws_ftp.ini . Его просто найти и прочитать, поскольку все записи сохраняются в текстовом формате, а пароли шифруются алгоритмом Triple DES после минимальной обфускации. В большинстве версий достаточно просто отбросить первый байт.

Расшифровать такие пароли легко с помощью утилиты WS_FTP Password Decryptor или бесплатного веб-сервиса .

Говоря о взломе произвольного сайта, обычно подразумевают получение пароля из логов и бэкапов конфигурационных файлов CMS или приложений для электронной коммерции. Если знаешь их типовую структуру, то легко сможешь указать ключевые слова. Строки, подобные встречающимся в ws_ftp.ini , крайне распространены. Например, в Drupal и PrestaShop обязательно есть идентификатор пользователя (UID) и соответствующий ему пароль (pwd), а хранится вся информация в файлах с расширением.inc. Искать их можно следующим образом:

"pwd=" "UID=" ext:inc

Раскрываем пароли от СУБД

В конфигурационных файлах SQL-серверов имена и адреса электронной почты пользователей хранятся в открытом виде, а вместо паролей записаны их хеши MD5. Расшифровать их, строго говоря, невозможно, однако можно найти соответствие среди известных пар хеш - пароль.

До сих пор встречаются СУБД, в которых не используется даже хеширование паролей. Конфигурационные файлы любой из них можно просто посмотреть в браузере.

Intext:DB_PASSWORD filetype:env

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

Filetype:reg HKEY_CURRENT_USER "Password"=

Не забываем про очевидное

Иногда добраться до закрытой информации удается с помощью случайно открытых и попавших в поле зрения Google данных. Идеальный вариант - найти список паролей в каком-нибудь распространенном формате. Хранить сведения аккаунтов в текстовом файле, документе Word или электронной таблице Excel могут только отчаянные люди, но как раз их всегда хватает.

Filetype:xls inurl:password

С одной стороны, есть масса средств для предотвращения подобных инцидентов. Необходимо указывать адекватные права доступа в htaccess, патчить CMS, не использовать левые скрипты и закрывать прочие дыры. Существует также файл со списком исключений robots.txt, запрещающий поисковикам индексировать указанные в нем файлы и каталоги. С другой стороны, если структура robots.txt на каком-то сервере отличается от стандартной, то сразу становится видно, что на нем пытаются скрыть.

Список каталогов и файлов на любом сайте предваряется стандартной надписью index of. Поскольку для служебных целей она должна встречаться в заголовке, то имеет смысл ограничить ее поиск оператором intitle . Интересные вещи находятся в каталогах /admin/, /personal/, /etc/ и даже /secret/.

Следим за обновлениями

Актуальность тут крайне важна: старые уязвимости закрывают очень медленно, но Google и его поисковая выдача меняются постоянно. Есть разница даже между фильтром «за последнюю секунду» (&tbs=qdr:s в конце урла запроса) и «в реальном времени» (&tbs=qdr:1).

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

По виду адресной строки можно догадаться только о способе ограничить вывод результатов с помощью конструкции &tbs=qdr: . Буква y после нее задает лимит в один год (&tbs=qdr:y), m показывает результаты за последний месяц, w - за неделю, d - за прошедший день, h - за последний час, n - за минуту, а s - за секунду. Самые свежие результаты, только что ставшие известными Google, находится при помощи фильтра &tbs=qdr:1 .

Если требуется написать хитрый скрипт, то будет полезно знать, что диапазон дат задается в Google в юлианском формате через оператор daterange . Например, вот так можно найти список документов PDF со словом confidential, загруженных c 1 января по 1 июля 2015 года.

Confidential filetype:pdf daterange:2457024-2457205

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

Таргетируемся и снова фильтруем

Помимо указания дополнительных операторов в поисковом запросе их можно отправлять прямо в теле ссылки. Например, уточнению filetype:pdf соответствует конструкция as_filetype=pdf . Таким образом удобно задавать любые уточнения. Допустим, выдача результатов только из Республики Гондурас задается добавлением в поисковый URL конструкции cr=countryHN , а только из города Бобруйск - gcs=Bobruisk . В разделе для разработчиков можно найти полный список .

Средства автоматизации Google призваны облегчить жизнь, но часто добавляют проблем. Например, по IP пользователя через WHOIS определяется его город. На основании этой информации в Google не только балансируется нагрузка между серверами, но и меняются результаты поисковой выдачи. В зависимости от региона при одном и том же запросе на первую страницу попадут разные результаты, а часть из них может вовсе оказаться скрытой. Почувствовать себя космополитом и искать информацию из любой страны поможет ее двухбуквенный код после директивы gl=country . Например, код Нидерландов - NL, а Ватикану и Северной Корее в Google свой код не положен.

Часто поисковая выдача оказывается замусоренной даже после использования нескольких продвинутых фильтров. В таком случае легко уточнить запрос, добавив к нему несколько слов-исключений (перед каждым из них ставится знак минус). Например, со словом Personal часто употребляются banking , names и tutorial . Поэтому более чистые поисковые результаты покажет не хрестоматийный пример запроса, а уточненный:

Intitle:"Index of /Personal/" -names -tutorial -banking

Пример напоследок

Искушенный хакер отличается тем, что обеспечивает себя всем необходимым самостоятельно. Например, VPN - штука удобная, но либо дорогая, либо временная и с ограничениями. Оформлять подписку для себя одного слишком накладно. Хорошо, что есть групповые подписки, а с помощью Google легко стать частью какой-нибудь группы. Для этого достаточно найти файл конфигурации Cisco VPN, у которого довольно нестандартное расширение PCF и узнаваемый путь: Program Files\Cisco Systems\VPN Client\Profiles . Один запрос, и ты вливаешься, к примеру, в дружный коллектив Боннского университета.

Filetype:pcf vpn OR Group

INFO

Google находит конфигурационные файлы с паролями, но многие из них записаны в зашифрованном виде или заменены хешами. Если видишь строки фиксированной длины, то сразу ищи сервис расшифровки.

Пароли хранятся в зашифрованном виде, но Морис Массар уже написал программу для их расшифровки и предоставляет ее бесплатно через thecampusgeeks.com .

При помощи Google выполняются сотни разных типов атак и тестов на проникновение. Есть множество вариантов, затрагивающих популярные программы, основные форматы баз данных, многочисленные уязвимости PHP, облаков и так далее. Если точно представлять то, что ищешь, это сильно упростит получение нужной информации (особенно той, которую не планировали делать всеобщим достоянием). Не Shodan единый питает интересными идеями, но всякая база проиндексированных сетевых ресурсов!

В предыдущей статье мы применили атрибут Authorize для класса контроллера Account, который ограничивает допуск к методам действий для неавторизованных пользователей. В этой статье я покажу вам, как доработать систему авторизации, чтобы осуществить более полный контроль над тем, какие действия можно выполнять определенным пользователям. По традиции, я составил список из трех вопросов, которые у вас сразу могут возникнуть:

Что это?

Авторизация - это процесс предоставления доступа к контроллерам и методам действий для определенных пользователей, как правило, находящихся в определенных ролях (например, допуск к админке должны иметь только администраторы).

Зачем нужно использовать?

Без авторизации вы сможете различать только две категории пользователей: прошедшие и не прошедшие аутентификацию. Большинство приложений имеют список ролей, таких как: пользователь, модератор, администратор и т. д.

Как использовать в рамках MVC?

Добавление поддержки ролей

ASP.NET Identity содержит строго типизированный базовый класс для доступа и управления ролями, который называется RoleManager , где T является реализацией интерфейса IRole , описывающего механизм хранения данных, используемых для представления ролей. Entity Framework использует класс IdentityRole , являющийся реализацией интерфейса IRole и содержит следующие свойства:

Мы не будем использовать напрямую объекты IdentityRole в нашем приложении, вместо этого добавьте файл класса AppRole.cs в папку Models со следующим содержимым:

Using Microsoft.AspNet.Identity.EntityFramework; namespace Users.Models { public class AppRole: IdentityRole { public AppRole() : base() { } public AppRole(string name) : base(name) { } } }

Класс RoleManager работает с экземплярами IRole с помощью методов и свойств, перечисленных в таблице ниже:

Эти базовые методы реализуют тот же базовый шаблон, который использует класс UserManager для управления пользователями. Добавьте файл AppRoleManager.cs в папку Infrastructure со следующим содержимым:

Using Microsoft.AspNet.Identity; using Microsoft.AspNet.Identity.EntityFramework; using Microsoft.AspNet.Identity.Owin; using Microsoft.Owin; using System; using Users.Models; namespace Users.Infrastructure { public class AppRoleManager: RoleManager, IDisposable { public AppRoleManager(RoleStore store) : base(store) { } public static AppRoleManager Create(IdentityFactoryOptions options, IOwinContext context) { return new AppRoleManager(new RoleStore(context.Get())); } } }

Этот класс определяет статический метод Create(), который позволит OWIN создавать экземпляры класса AppRoleManager для всех запросов, где требуются данные Identity, не раскрывая информации о том, как данные о ролях хранятся в приложении. Чтобы зарегистрировать класс управления ролями в OWIN, необходимо отредактировать файл IdentityConfig.cs, как показано в примере ниже:

// ... namespace Users { public class IdentityConfig { public void Configuration(IAppBuilder app) { // ... app.CreatePerOwinContext(AppRoleManager.Create); // ... } } }

Это гарантирует, что экземпляры класса AppRoleManager используют тот же контекст базы данных Entity Framework, что и экземпляры AppUserManager.

Создание и удаление ролей

Мы подготовили базовую инфраструктуру для работы с ролями, давайте теперь создадим средство администрирования для работы с ролями. Сначала давайте определим методы действия и представления для управления ролями. Добавьте контроллер RoleAdmin в проект приложения с кодом, показанным в примере ниже:

Using System.Web; using System.Web.Mvc; using System.Threading.Tasks; using Microsoft.AspNet.Identity; using Microsoft.AspNet.Identity.Owin; using System.ComponentModel.DataAnnotations; using Users.Infrastructure; using Users.Models; namespace Users.Controllers { public class RoleAdminController: Controller { private AppUserManager UserManager { get { return HttpContext.GetOwinContext().GetUserManager(); } } private AppRoleManager RoleManager { get { return HttpContext.GetOwinContext().GetUserManager(); } } public ActionResult Index() { return View(RoleManager.Roles); } public ActionResult Create() { return View(); } public async Task Create(string name) { if (ModelState.IsValid) { IdentityResult result = await RoleManager.CreateAsync(new AppRole(name)); if (result.Succeeded) { return RedirectToAction("Index"); } else { AddErrorsFromResult(result); } } return View(name); } public async Task Delete(string id) { AppRole role = await RoleManager.FindByIdAsync(id); if (role != null) { IdentityResult result = await RoleManager.DeleteAsync(role); if (result.Succeeded) { return RedirectToAction("Index"); } else { return View("Error", result.Errors); } } else { return View("Error", new string { "Роль не найдена" }); } } private void AddErrorsFromResult(IdentityResult result) { foreach (string error in result.Errors) { ModelState.AddModelError("", error); } } } }

Здесь мы применили многие из тех приемов, что использовали в контроллере Admin, в том числе добавили свойства UserManager и RoleManager для более быстрого запроса объектов AppRoleManager и AppUserManager. Также мы добавили аналогичный метод AddErrorsFromResult(), который обрабатывает ошибки в объекте IdentityResult и добавляет их в метаданные модели.

Представления для контроллера RoleAdmin содержат простую HTML-разметку и операторы Razor. Нам необходимо отобразить не только список ролей, но и имена всех пользователей, входящих в каждую роль. Класс IdentityRole определяет свойство Users, которое возвращает коллекцию объектов IdentityUserRole , описывающих пользователей роли. Каждый объект IdentityUserRole имеет свойство UserId, которое возвращает уникальный идентификатор пользователя, с помощью которого мы будем получать имя пользователя.

Добавьте файл класса IdentityHelpers.cs в папку Infrastructure со следующим содержимым:

Using System.Web; using System.Web.Mvc; using Microsoft.AspNet.Identity.Owin; namespace Users.Infrastructure { public static class IdentityHelpers { public static MvcHtmlString GetUserName(this HtmlHelper html, string id) { AppUserManager mgr = HttpContext.Current .GetOwinContext().GetUserManager(); return new MvcHtmlString(mgr.FindByIdAsync(id).Result.UserName); } } }

Этот код содержит определение вспомогательного метода HTML , определенного как расширение класса HtmlHelper. Метод GetUserName() принимает строковый аргумент, содержащий идентификатор пользователя, получает экземпляр класса AppUserManager с помощью метода GetOwinContext().GetUserManager() (где метод GetOwinContext является расширяющим HttpContext), использует метод FindByIdAsync(), чтобы найти экземпляр AppUser, связанный с идентификатором и возвращает значение свойства UserName.

Следующий пример показывает содержимое файла Index.cshtml, находящегося в папке /Views/RoleAdmin:

@using Users.Models @using Users.Infrastructure @model IEnumerable @{ ViewBag.Title = "Роли"; }

Roles
@if (Model.Count() == 0) { } else { foreach (AppRole role in Model) { } }
ID Название Пользователи
Нет ролей
@role.Id @role.Name @if (role.Users == null || role.Users.Count == 0) { @: Нет пользователей в этой роли } else {

@string.Join(", ", role.Users.Select(x => Html.GetUserName(x.UserId)))

}
@using (Html.BeginForm("Delete", "RoleAdmin", new { id = role.Id })) { @Html.ActionLink("Изменить", "Edit", new { id = role.Id }, new { @class = "btn btn-primary btn-xs", style= "float:left; margin-right:5px" }) }
@Html.ActionLink("Создать", "Create", null, new { @class = "btn btn-primary" })

В этом представлении отображается список ролей, определенных в приложении, вместе со списком пользователей в каждой роли. На данный момент мы еще не создали ни одной роли:

Следующий пример содержит представление Create.cshtml в той же папке, которое используется для создания новых ролей:

@model string @{ ViewBag.Title = "Создание роли"; }

Создать роль

@Html.ValidationSummary(false) @using (Html.BeginForm()) {

Единственная информация, которая требуется для создания новой роли - ее название. Поэтому мы добавили один стандартный элемент и кнопку отправки формы POST-методу действия Create.

Чтобы протестировать функционал создания ролей, запустите приложение и перейдите по адресу /RoleAdmin/Index в окне браузера. Чтобы создать новую роль нажмите кнопку «Создать», введите имя в поле ввода в появившейся форме и нажмите вторую кнопку «Создать». Новое представление будет отображать список ролей, сохраненных в базе данных:

Вы можете также удалить роль из приложения нажав кнопку «Удалить».

Редактирование ролей

Для авторизации пользователей недостаточно просто создавать и удалять роли. Мы также должны уметь управлять ролями, назначать и удалять пользователей из роли. Это не сложный процесс, но для его реализации нам необходимо загружать данные о ролях с помощью класса AppRoleManager, а затем вызывать методы, определенные в классе AppUserManager на объектах, связанных с определенной ролью.

Давайте начнем с добавления новых классов модели-представления (view-model) в файл UserViewModels.cs:

Using System.Collections.Generic; using System.ComponentModel.DataAnnotations; namespace Users.Models { public class CreateModel { // ... } public class LoginViewModel { // ... } public class RoleEditModel { public AppRole Role { get; set; } public IEnumerable Members { get; set; } public IEnumerable NonMembers { get; set; } } public class RoleModificationModel { public string RoleName { get; set; } public string IdsToAdd { get; set; } public string IdsToDelete { get; set; } } }

Класс RoleEditModel содержит информацию о роли и определяет список пользователей в роли в виде коллекции объектов AppUser. Благодаря этому, мы сможем извлечь ID и имя каждого пользователя в роли. Класс RoleModificationModel будет получать данные от системы привязки модели во время редактирования данных пользователя. Он содержит массив идентификаторов пользователей, а не объектов AppUser, для замены ролей.

Определившись с классами моделей, давайте добавим методы редактирования ролей Edit в контроллер RoleAdmin:

Using System.Web; using System.Web.Mvc; using System.Threading.Tasks; using Microsoft.AspNet.Identity; using Microsoft.AspNet.Identity.Owin; using System.ComponentModel.DataAnnotations; using Users.Infrastructure; using Users.Models; using System.Linq; using System.Collections.Generic; namespace Users.Controllers { public class RoleAdminController: Controller { // ... public async Task Edit(string id) { AppRole role = await RoleManager.FindByIdAsync(id); string memberIDs = role.Users.Select(x => x.UserId).ToArray(); IEnumerable members = UserManager.Users.Where(x => memberIDs.Any(y => y == x.Id)); IEnumerable nonMembers = UserManager.Users.Except(members); return View(new RoleEditModel { Role = role, Members = members, NonMembers = nonMembers }); } public async Task Edit(RoleModificationModel model) { IdentityResult result; if (ModelState.IsValid) { foreach (string userId in model.IdsToAdd ?? new string { }) { result = await UserManager.AddToRoleAsync(userId, model.RoleName); if (!result.Succeeded) { return View("Error", result.Errors); } } foreach (string userId in model.IdsToDelete ?? new string { }) { result = await UserManager.RemoveFromRoleAsync(userId, model.RoleName); if (!result.Succeeded) { return View("Error", result.Errors); } } return RedirectToAction("Index"); } return View("Error", new string { "Роль не найдена" }); } } }

Большая часть кода в GET-версии метода Edit отвечает за формирование списков пользователей входящих и не входящих в роль и реализуется с помощью методов LINQ. После группировки пользователей возвращается представление, которому передается объект RoleEditModel.

POST-версия метода Edit отвечает за добавление и удаление пользователей из ролей. Класс AppUserManager наследует ряд вспомогательных методов для работы с ролями из класса UserManager. Эти методы перечислены в таблице ниже:

Странность этих методов заключается в том, что они работают с идентификатором пользователя и именем роли, хотя каждая роль также имеет свой уникальный идентификатор. Именно поэтому класс RoleModificationModel содержит строковое свойство RoleName.

В примере ниже показан код представления Edit.cshtml, находящегося в папке /Views/RoleAdmin.cshtml:

@using Users.Models @model RoleEditModel @{ ViewBag.Title = "Изменить роль"; }

Изменить роль

@Html.ValidationSummary() @using (Html.BeginForm()) {
Добавить в роль @Model.Role.Name
@if (Model.NonMembers.Count() == 0) { } else { foreach (AppUser user in Model.NonMembers) { } }
Все пользователи в роли
User ID Добавить в роль
@user.UserName
Удалить из роли @Model.Role.Name
@if (Model.Members.Count() == 0) { } else { foreach (AppUser user in Model.Members) { } }
Нет пользователей в роли
User ID Удалить из роли
@user.UserName
@Html.ActionLink("Отмена", "Index", null, new { @class = "btn btn-default" }) }

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

Давайте протестируем функциональность редактирования ролей. Добавление класса AppRoleManager в архитектуру OWIN заставит Entity Framework удалить базу данных и воссоздать новую схему. Это означает, что пользователи, которых мы создали ранее исчезнут. Поэтому после запуска приложения перейдите по адресу /Admin/Index и создайте нескольких пользователей.

Чтобы проверить редактирование ролей, перейдите по адресу /RoleAdmin/Index и создайте несколько ролей, затем отредактируйте эти роли, добавив в них нескольких пользователей. На рисунке ниже показан пример приложения (я создал роль Users):

Использование ролей для авторизации

Теперь, когда у нас есть возможность управления ролями, мы можем использовать их в качестве основы для авторизации через атрибут Authorize. Чтобы проще было тестировать процесс авторизации, давайте добавим метод действия для выхода пользователя из системы в контроллер Account, как показано в примере ниже:

Public class AccountController: Controller { // ... public ActionResult Logout() { AuthManager.SignOut(); return RedirectToAction("Index", "Home"); } // ... }

Давайте обновим контроллер Home и добавим новый метод действия, который будет передавать информацию об аутентифицированном пользователе в представление:

Using System.Collections.Generic; using System.Web.Mvc; namespace Users.Controllers { public class HomeController: Controller { public ActionResult Index() { return View(GetData("Index")); } public ActionResult OtherAction() { return View("Index", GetData("OtherAction")); } private Dictionary GetData(string actionName) { Dictionary dict = new Dictionary(); dict.Add("Action", actionName); dict.Add("Пользователь", HttpContext.User.Identity.Name); dict.Add("Аутентифицирован?", HttpContext.User.Identity.IsAuthenticated); dict.Add("Тип аутентификации", HttpContext.User.Identity.AuthenticationType); dict.Add("В роли Users?", HttpContext.User.IsInRole("Users")); return dict; } } }

В этом примере мы оставили атрибут Authorize для метода действия Index без изменений, но добавили этот атрибут к методу OtherAction, задав при этом свойство Roles, ограничивающее доступ к этому методу только для пользователей, являющихся членами роли Users. Мы также добавили метод GetData(), который добавляет некоторую базовую информацию о пользователе, используя свойства, доступные через объект HttpContext.

В заключение, нам необходимо добавить кнопку выхода из приложения в представление Index.cshtml из папки /Views/Home:

... @Html.ActionLink("Выйти", "Logout", "Account", null, new {@class = "btn btn-primary"})

Атрибут Authorize может быть также использован для настройки авторизации на основе списка пользователей. Данную возможность удобно использовать в небольших проектах, но это создаст трудности при расширении приложения, т. к. каждый раз потребуется изменять код в контроллере, когда будет добавляется новый пользователь. Использование ролей для авторизации изолирует приложение от изменений в учетных записях отдельных пользователей и контролирует доступ к приложению через членство ролей.

Для тестирования системы авторизации, запустите приложение и перейдите по адресу /Home/Index. Браузер будет перенаправлен на страницу входа в приложение, где вы должны будете ввести данные существующей учетной записи. Метод действия Index является доступным для любого авторизованного пользователя. Однако если вы перейдете по адресу /Index/OtherAction, доступ будет открыт только тем пользователям, которые являются членами роли Users.

Если вы попытаетесь войти под пользователем, находящимся в другой роли, то браузер перенаправит вас снова на форму входа в приложение. Перенаправление уже аутентифицированных пользователей на страницу входа является малополезным решением, поэтому давайте отредактируем контроллер Account и добавим возможность перенаправления аутентифированных пользователей, не прошедших авторизацию, на страницу ошибки:

Public class AccountController: Controller { public ActionResult Login(string returnUrl) { if (HttpContext.User.Identity.IsAuthenticated) { return View("Error", new string { "В доступе отказано" }); } ViewBag.returnUrl = returnUrl; return View(); } // ... }

На рисунке ниже наглядно показано поведение нашего приложения, когда пользователю отказано в доступе:

Используйте события , чтобы узнавать, как пользователи взаимодействуют с вашим контентом.

Событие – это взаимодействие пользователя с контентом, которое можно отслеживать независимо от просмотров страниц или экранов. Скачивания файлов, клики по мобильным объявлениям, использование гаджетов, элементов Flash и AJAX, воспроизведение видео – все эти действия можно отслеживать в качестве событий.

Содержание

Просмотр данных о событиях

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

Чтобы просмотреть отчеты о событиях, выполните следующие действия:

  1. Выберите нужное представление .
  2. Откройте Отчеты .
  3. Выберите Поведение > События .

Компоненты событий

Событие состоит из следующих компонентов. Если событие произошло, для каждого из компонентов регистрируется значение, которое появляется в отчетах:

  • Категория
  • Действие
  • Ярлык (необязательно, но рекомендуется)
  • Значение (необязательно)

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

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

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

В этом случае в отчетах будет только одна категория – Videos (Видеозаписи) – и вы увидите сводные показатели взаимодействия пользователей со всеми элементами этого видеообъекта.

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

С другой стороны, можно создать отдельные категории для видеозаписей разных типов: одну – для кинофильмов, другую – для музыкальных видеоклипов, и т. д. Можно также создать отдельную категорию для скачивания видео:

  • Видео – фильмы
  • Видео – музыка
  • Скачивание видео

Тогда в отчете будет показано общее количество событий во всех трех категориях. Показатель Всего событий – это количество всех событий во всех категориях, указанных в реализации отслеживания. Однако вы не сможете увидеть объединенные показатели по всем видеозаписям отдельно от скачивания видео, так как данные отдельных событий объединены в соответствующих категориях.

Объектная модель отслеживания событий обеспечивает максимальную гибкость, но все же мы рекомендуем сначала продумать структуру отчетов, а затем выбирать названия категорий. Если вы будете повторно использовать название категории, не используйте другие варианты названия. Например, если для отслеживания видео вы добавите категорию Video, а затем в названии по ошибке используете множественное число (Videos), то у вас будет две разных категории для отслеживания видео. Кроме того, если вы измените название категории объекта, который уже отслеживается, данные по исходной категории не будут изменены. Поэтому в отчетах показатели одного элемента страницы будут представлены в двух разных категориях.

Действие

Обычно параметр "Действие" используется для обозначения отслеживаемого события или взаимодействия, связанного с веб-объектом. Например, с помощью этого параметра можно отслеживать в одной категории Videos (Видеозаписи) несколько событий:

  • Время завершения загрузки видео
  • Нажатия кнопки "Воспроизведение"
  • Нажатия кнопки "Стоп"
  • Нажатия кнопки "Пауза"
  • Все действия перечисляются независимо от своих родительских категорий. Это удобно для сегментирования данных событий в отчетах.
  • Уникальное событие определяется уникальным именем действия. В разных категориях можно использовать одинаковые названия действий, но это может повлиять на расчет количества уникальных событий. Подробнее об этом можно узнать в разделах "Рекомендации" и "Неявный подсчет" ниже.

Ярлыки

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

Эти компоненты событий, подобно категориям и действиям, можно просматривать в отдельном отчете, где собраны все созданные вами ярлыки. Ярлык можно рассматривать как дополнительный параметр взаимодействия пользователя с объектами страницы. Предположим, вам нужно отслеживать взаимодействие с пятью проигрывателями видео на странице сайта. Каждый из этих проигрывателей может использовать категорию Videos (Видеозаписи) с действием Play (Воспроизведение), но для каждого можно также создать отдельный ярлык (например, с названием фильма), и они будут представлены в отчете как отдельные элементы.

Чтобы отчеты были максимально эффективны, следуйте приведенным ниже рекомендациям.

  • Названия действий должны соответствовать данным отчета. При отслеживании событий показатели для действий с одним названием из двух разных категорий объединяются. Например, если действие под названием Click (Клик) используется в категории Downloads (Скачивание) и в категории Videos (Видеозаписи), то показатели для него в отчете "Основные действия" отображаются по всем взаимодействиям с этим названием. Подробные данные для действия Click (Клик) по категориям можно просмотреть на следующем уровне отчета. Однако неосмотрительное использование действия Click (Клик) в отслеживании различных событий снижает эффективность работы с отчетами. Если вы отслеживаете большое количество событий на сайте, выбирайте для действий имена, которые отражают категории отслеживаемых данных. Например, название Click (Клик) можно использовать для взаимодействия с гаджетами, а для действий с проигрывателем – названия Play (Воспроизведение), Pause (Пауза) и Stop (Стоп).
  • Используйте глобальные названия действий, чтобы получать сводные и раздельные данные по взаимодействиям пользователей. Например, можно использовать название Play (Воспроизведение) в категории Videos (Видеозаписи) для всех видеозаписей на сайте. Тогда отчет "Основные действия" будет содержать сводные данные о действии "Воспроизведение", и вы сможете сравнить это событие с другими событиями в видеозаписях, например "Пауза" или "Стоп".

    Ещё один пример. Допустим, вы хотите использовать в отчетах одну категорию видео, но при этом получать информацию о двух интерфейсах воспроизведения. В таком случае можно использовать название действия, чтобы различать данные о разных интерфейсах, не создавая две отдельные категории видео. Так вы сможете различать нужные данные, и при этом у вас будет сводная статистика по всем видеороликам сайта.

  • "Действие" не всегда означает действие. В качестве значения этого компонента можно использовать любую строку. В некоторых случаях название события или действия не очень информативно, поэтому для отслеживания других элементов можно использовать параметр действия. Например, если требуется отслеживать скачивание файлов на странице, в качестве параметра действия для события скачивания можно указать тип файла документа. В этом случае отчеты по категории Downloads (Скачивание) будут разбиты по типам файлов (PDF, DOC, XLS).
  • Количество уникальных событий увеличивается только за счет уникальных действий. Каждое взаимодействие пользователя с объектом, помеченным определенным названием действия, регистрируется как одно уникальное событие, связанное с этим названием. Любое дополнительное взаимодействие с тем же триггером действия в рамках одного сеанса не влияет на подсчет уникальных событий, связанных с этим действием. Даже если пользователь выполнит действие с этим названием на другом объекте, количество уникальных событий не изменится.

    Поэтому при работе с отчетами нужно учитывать два важных фактора. Во-первых, предположим, что пользователь выполняет действие Play (Воспроизведение) в двух разных проигрывателях, отнесенных к разным категориям. В отчетах "Основные действия" для Play (Воспроизведение) будет указано одно уникальное событие, хотя пользователь взаимодействовал с двумя уникальными проигрывателями. Во-вторых, в отчете по действиям из каждой категории будет указано одно уникальное действие, потому что фактически на каждую пару "категория-действие" приходится одно уникальное событие. Подробнее об этом можно узнать в разделе "Неявный подсчет" ниже.

Значения

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

Значение – это численная величина. Значения всех событий суммируются в отчете (см. раздел "Неявный подсчет" ниже). В отчете также определяется среднее значение для категории. В примере выше событие вызывается для действия "Время загрузки видео" сразу после завершения загрузки видеозаписи. Название видео указывается в ярлыке, а значение увеличивается с каждой загрузкой. После этого можно определить среднее время загрузки для всех действий "Время загрузки видео" из категории "Видеозаписи". Предположим, что у вас 5 уникальных загрузок видеозаписей с сайта со следующими значениями времени загрузки в секундах:

В этом случае среднее время загрузки в отчете подсчитывается так:
  • Сеансы с событиями: 5.
  • Значение: 53.
  • Среднее значение: 10,6.

Отрицательные значения не поддерживаются.

События без взаимодействия

Термин "без взаимодействия" относится к необязательному логическому параметру, который может быть передан методу, отправляющему событие. С помощью этого параметра вы можете задать, как должен определяться показатель отказов для страниц на сайте, на которых используется отслеживание событий. Предположим, у вас на главной странице есть встроенное видео и вы хотите узнать показатель отказов для этой страницы. Что следует считать отказом? Важно ли для вас взаимодействие с роликом на главной странице? Если да, то такое взаимодействие должно учитываться при подсчете показателя отказов. Сеансы, включающие только главную страницу с нажатием на видео, не должны считаться отказами. Если же вы хотите узнать показатель отказов для главной страницы независимо от взаимодействия с видео, тогда при подсчете отказов вам нужно исключить взаимодействия с видео.

В этом случае вам понадобится необязательный параметр, позволяющий не учитывать взаимодействия. Напомним, что отказом считается сеанс, в течение которого было выполнено только одно взаимодействие. По умолчанию событие считается взаимодействием и тоже учитывается при подсчете показателя отказов. Однако если этому параметру присвоено значение true, то событие такого типа не считается взаимодействием. Этот факт можно использовать для корректировки показателя отказов на страницах с событиями. Если параметру присвоено значение true, это значит, что сеанс, содержащий единственную страницу, помеченную событиями без взаимодействий, считается отказом, даже если посетитель запустил событие. И наоборот: когда этот параметр не используется, сеанс не считается отказом, если пользователь посещает только одну страницу, на которой отслеживаются события, и запускает событие.

Неявный подсчет

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

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

В таблице ниже показано, как в интерфейсе отчетов объединяются данные по определенной категории событий. В этом примере одно название категории используется в двух разных проигрывателях, каждому из которых присвоен свой ярлык. Здесь используются одинаковые действия Play (Воспроизведение) и Stop (Стоп), запрограммированные во Flash-интерфейсе проигрывателей.

Отслеживание событий для категории Videos (Видеозаписи)

Действие Ярлык: Gone With the Wind (Унесенные ветром) Ярлык: Mr Smith Goes to Washington (Мистер Смит едет в Вашингтон) Всего
Play (Воспроизведение)

22 клика в 10 сеансах с событием

7 кликов в 5 сеансах с событием

29 событий всего

15 уникальных событий Play (Воспроизведение)

Pause (Пауза)

3 клика в 2 сеансах с событием

16 кликов в 8 сеансах с событием

19 событий всего

10 уникальных событий Pause (Пауза)

Stop (Стоп)

2 клика в 2 сеансах с событием

4 клика в 3 сеансах с событием

6 событий всего

5 уникальных событий Stop (Стоп)

Всего

27 событий всего

14 уникальных событий для Gone With the Wind

27 событий всего

16 уникальных событий для Mr Smith Goes to Washington

54 события всего

30 уникальных событий для категории Videos

О чем важно помнить

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

Влияние на показатель отказов

Обычно отказом считается сеанс, во время которого пользователь посетил только одну страницу сайта. В Google Аналитике отказом считается сеанс, в ходе которого был выполнен только один запрос GIF (например, если пользователь открыл одну страницу сайта и покинул его, не отправив других запросов к серверу Google Аналитики в рамках этого сеанса). Однако для страниц, на которых используется отслеживание событий, показатель отказов может изменяться. Это объясняется тем, что отслеживание событий, как и отслеживание страниц, классифицируется как запрос взаимодействия.

Предположим, что у вас есть страница с проигрывателем видео, для которой показатель отказов всегда был высоким, и вы не отслеживаете события на ней. Если вы настроите отслеживание событий для этого проигрывателя, то показатель отказов для страницы может уменьшиться, потому что Google Аналитика будет фиксировать взаимодействия пользователя с проигрывателем и отправлять дополнительный запрос к серверу для таких взаимодействий. Таким образом, доля посетителей, которые покидают сайт, не просматривая другие страницы, может оставаться прежней, но в результате их взаимодействия с проигрывателем запускаются вызовы отслеживания событий, и такие посещения не рассматриваются как отказы.

Поэтому для страниц с отслеживанием событий отказом считается посещение одной страницы сайта без взаимодействия с отслеживаемыми событиями.

Важно! Если взаимодействием считается загрузка страницы, то показатель отказов для этой страницы будет равен нулю.

Ограничение по количеству событий за сеанс

ga.js

Первые 10 событий, отправленных в Google Аналитику, обрабатываются сразу. Затем выполняется обработка не более одного события в секунду. За сеанс может быть обработано не более 500 событий.

analytics.js и gtag.js

Первые 20 событий, отправленных в Google Аналитику, обрабатываются сразу. Затем выполняется обработка не более двух событий в секунду. За сеанс может быть обработано не более 500 событий. Это ограничение распространяется на все обращения, за исключением типов item и transaction (данные по товарам и транзакциям).

Чтобы число обращений оставалось в пределах установленных ограничений, не рекомендуется делать следующее:

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

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

  • Заранее определите, для каких элементов вам может понадобиться отслеживать данные, даже если сейчас вас интересует только один объект на сайте. Это поможет вам разработать структуру отчетности, в рамках которой вы позднее сможете отслеживать сколько угодно событий любого типа.
  • Планируя отчеты по отслеживанию событий, обсудите все детали с теми, для кого эти отчеты предназначены. Четко понимая, что должно быть представлено в отчетах, вы сможете правильно реализовать отслеживание событий. Например, если в отчетах нужно отразить только взаимодействие с интерфейсом просмотра видео, структура категорий будет значительно отличаться от ситуации, когда требуется отслеживать другие элементы интерфейса на базе Flash, например меню, встроенные гаджеты и время загрузки. Кроме того, советуем обсудить с пользователями отчетов разные возможности отслеживания событий и выбрать наиболее подходящий вариант. Например, им может быть интересно не только взаимодействие пользователей с Flash-интерфейсом видеороликов, но и время их загрузки. Поэтому нужно заранее продумать, какие названия будут использоваться в вызовах событий.
  • Используйте точные и понятные названия: все названия категорий, действий и ярлыков, которые вы используете для отслеживания событий, отображаются в интерфейсе отчетов. Кроме того, в отчетах нельзя использовать одинаковые пары "категория-действие", поэтому заранее обдумайте, как будут рассчитываться показатели для всех объектов одной категории.

Чем отличаются события от целей-событий

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

Цель-событие – это заданная вами , определяющая событие как конверсию.

Была ли эта статья полезна?

Как можно улучшить эту статью?

    Webasyst-приложение «Рассылки» умеет автоматически подсчитывать количество просмотров отправленного вами сообщения получателями. Чтобы использовать эту возможность, достаточно добавить любое изображение в сообщение с помощью встроенного визуального...

    Есть решение

    Чтобы это работало, нужно добавлять изображения через визуальный редактор, при создании рассылки. Подробнее об этом написано в статье Как узнать, сколько получателей прочитали ваше email-сообщение на нашем сайте.

    На странице просмотра отчета об отправленном сообщении в приложении «Рассылки» вы увидите, что все получатели распределены в несколько категорий, как показано на рисунке: Исключения Прочитано Отписались Отказы Неизвестно...

    В приложении «Рассылки» есть встроенная функция, которая позволяет определять, сколько получателей email-рассылки прочитали ваше сообщение.Загрузка изображенийДля сбора такой информации используются изображения, вставленные в текст сообщения. Каждый...

    Введение Данное сообщение - не вопрос. Это, скорее, статья об одном из способов выжать из своего интернет-магазина больше производительности. Целевая аудитория статьи - пользователи с навыками администрирования и владельцы магазинов, у которых в...

    Прочитал 3 похожих темы - куда ни глянь все сидят и пилят данный плагин с 2013 года. На сайте деловых, поговаривают, запрещают делать модули на базе их апи платными, но мне, честно говоря, пофигу.Вопрос к разработчикам, тп, экспертам и..отправлятелям...

    +2

    Здравствуйте. В приложении "Рассылки" не увидел возможности скачать список emailов клиентов, которые прочитали письмо. Есть возможность выгружать по 50 штук, но при нескольких сотнях прочитанных сообщений это займет много времени.Для чего это...

    Есть решение

    Ерунда такая с моей рассылкой. Если отправляю тестовую рассылку и пишу там пару выдуманых почтовых ящиков то в отчете рассылки показаны отказы. А когда отправляю своим подписчикам 2500 то нет ни одного отказа зато 70% неизвестно. Прочитано:663(30%)...

    Ваще-то, я должен сказать, 30% прочитано и 70% неизвестно - это весьма и весьма достойный результат. База адресов вполне живая. Я почти готов поверить, что там может и не быть битых ящиков.Когда будете отправлять следующую живую, не тестовую рассылку, добавьте туда вперемешку пару битых адресов (но чтобы не полная абракадабра, а которые выглядят как хорошие) и пару своих хороших адресов. Другого способа убедиться в том, что всё хорошо, я не могу придумать.Давайте ещё я опишу жизненный путь Email письма....

    -8 Не принято

    Предлагаю, чтобы плагины и приложения разработчиков перед продажей шифровались (обфусцировались) после проверки WebAsyst. Чтобы нельзя было втупую купить плагин и завтра продавать "копию" за полцены от оригинала.

    +1 Просто крик души в оформление заказа

    Являемся разработчиками темы https://www.webasyst.ru/store/theme/juicer_land/ в которой мы переделали оформление заказа, в частности доставка была представлена в виде вкладок аккордиона, за основы была взята тема для разработчиков Dummy. В итоге...

    Здравствуйте. Есть необходимость скачивания списка "неизвестно" после проведения рассылки для повторной рассылки по этой базе. В данный момент приложение "рассылки" позволяет выгружать вручную по 50 email адресов. При базе в 50...

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

    Прием платежей в Shop-Script через платежную систему «Яндекс.Деньги» осуществляется с помощью плагина, который нужно установить с помощью приложения «Инсталлер». Полезно знать: подключаясь к платежной системе через Webasyst, вы...

    Добавить вкладку в админке

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

    подскажите как сгенерировать sitemap.xml для конкретного сайта на webasyst прочитал что framework делает это автоматически, но у меня есть сайт, а файла sitemap нет что конкретно нужно сделать, чтобы он появился

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

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

    Безопастность хеша паролей

    Добрый день, прочитал статью: http://www.webasyst.ru/blog/security-improvement-advices-1/ Хочу сделать кастомный алгоритм шифрования и добавить соль. В предлагаемой функции в статье кажется не правильно указана соль. По идее солью должно быть...

    Есть решение

    В логике работы плагина необходимо читать (писать) данные из основных таблиц приложения shop-script 5. Если я пишу и использую плагин только для себя, я могу просто напрямую из своей модели прочитать и записать данные в эти таблицы (тут все...

    Теоретически со временем поменяться может что угодно — всего заранее не предусмотришь. Например, вёрстка бекенда, к которой привязан плагин. Тут уж ничего не поделаешь — придётся адаптировать. Так же и в вашем случае. Если речь идёт о записи важной информации в базу данных, имеет смысл для таких действий использовать механизм исключений, чтобы с их помощью сигнализировать пользователю, если что-то пойдёт не так.

    Здравствуйте!У меня есть домен Lovere.ru. Сейчас он лежит на хостинге у другого провайдера.Создан сайт на вашей платформе http://lovere.host.webasyst.com/Меня все устроило и теперь я хочу открепить свой домен он своего хостера и положить свой домен к...

Похожие статьи