# Идентификация через передачу подписанных полей, версия 2.0

!!! Note "N.B."
    Вместо алгоритмов, описанных ниже, рекомендуется использовать токен. См ["Идентификация через токен"](https://webim.ru/kb/dev/identification/authorization-scheme-tokenizer.html).

Для передачи информации об авторизованном на сайте посетителе и дальнейшего её показа в интерфейсе оператора **Webim** необходимо добавить на страницы сайта следующий javascript-код:

```
webim_visitor = {
    fields: {
        имя поля: значение,
        имя поля: значение,
        ...
    },
    expires: timestamp,
    hash: "контрольная сумма"
};
```

Пример (алгоритм `HMAC-SHA256`):

```
webim_visitor = {
    fields: {
        id: "12345",
        display_name: "Евгений",
        phone: "+78123855337",
        email: "abc@webim.ru"
    },
    expires: 1481195621,
    hash: "07ef16b821f9552a8b3118416ed9ed6278d3a8ff93751d157c88edc1895cd86f"
};
```

Пример (алгоритм `SHA256`):

```
webim_visitor = {
    fields: {
        id: "12345",
        display_name: "Евгений",
        phone: "+78123855337",
        email: "abc@webim.ru"
    },
    expires: 1481195621,
    hash: "f859287203804f8f25123b3ea651338ac73cef970bec1066d061d75786c0dcb7"
};
```

Пример (алгоритм `sha-512`):

```
webim_visitor = {
    fields: {
        id: "12345",
        display_name: "Евгений",
        phone: "+78123855337",
        email: "abc@webim.ru"
    },
    expires: 1481195621,
    hash: "4ea919daf569bfe27144e33f84b58fcccf98379107c3024db7d0514963775cd600a603cb4dbb48e51a50825df62287b4eb52073c7a86b46b38c6fddcc6c8afbb"
};
```
!!! Note "N.B."
    Эти примеры и эти контрольные суммы посчитаны с использованием случайного ключа `e64e35642555f3ecd64ae7dbb600dca8`.

Контрольная сумма для Вашего аккаунта рассчитывается на основе приватного ключа, который находится в разделе **Настройки -> Приватные ключи**. Используется строковое представление приватного ключа, то есть `key=str(private_key)`.

!!! Note "N.B."
    Приватный ключ не должен быть доступен клиентам, подпись должна формироваться только на Вашем сервере. Иначе безопасность Ваших клиентов будет скомпрометирована.

Список поддерживаемых полей в `fields`:

  * `id` — ID посетителя (обязателен, уникален)

  * `display_name` — имя

  * `phone` — телефон

  * `email` — Email

  * `profile_url` — ссылка на профиль

  * `avatar_url` — сcылка на графический файл — аватарку

  * `login` — login посетителя на сайте

  * `comment` — комментарий

  * `info` — дополнительная информация

  * `high_priority` - приоритет посетителя

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

Можно передавать и другие поля (с собственными названиями), они будут отображаться в первом сообщении диалога и передаваться по API, но будут отсутствовать в РМО в панели с данными посетителя справа от диалога.

Поле `id` является обязательным (по нему идентифицируется пользователь в системе). Поле должно содержать уникальное значение, в противном случае пользователи с одинаковым `id` будут иметь доступ к сообщениям друг друга. Остальные поля — опциональные. В случае, если `id` посетителя изменяется, в системе он начинает считаться за нового посетителя или же за уже существующего посетителя в том случае, если его новый `id` не уникален.

Поле `high_priority` отражает приоритет чата, начатого этим посетителем. Если чат начат с [приоритетной страницы](https://webim.ru/kb/for-admins/high-priority-urls.html), то значение поля `high_priority` равно `1`. В другом случае поле может иметь любое другое значение. Также приоритет может устанавливаться клиентом вручную, если требуется, чтобы чаты от определённых посетителей обрабатывались в первую очередь. Например, такой подход может использоваться в мобильном приложении на основе **Webim Mobile SDK**.

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

При использовании этого параметра необходимо обеспечивать валидность предоставляемых данных на протяжении всего времени взаимодействия пользователя с системой: либо значение `expires` должно выбираться с большим запасом, либо объект с данным должен периодически обновляться по мере приближения момента времени, указанного в expires. Заполнение данного поля служит дополнительной системой защиты: в случае кражи данных злоумышленник не сможет авторизоваться по истечении указанного срока действия. То есть, посетитель не сможет осуществлять действия, а оператор всё ещё сможет отвечать ему и push-уведомления продолжат отправляться на указанный при создании сессии push-токен.

При необходимости выйти из авторизованной зоны раньше времени, указанного в `expires`, необходимо передать значение `null` в параметре `webim_visitor`.

Поле `hash` должно содержать контрольную сумму.

## Вычисление контрольной суммы { #hash-computing }

Для вычисления контрольной суммы необходимо:

  1. Отсортировать json-ключи полей (не значения) из `fields` в соответствии с алфавитным порядком имен полей.

  1. Сложить значения полей в одну строку.

  1. Если Вы используете `expires` — добавьте значение поля в конец.

  1. От полученной строки вычислить контрольную сумму с использованием приватного ключа аккаунта.

     Выбор алгоритма определяется системным параметром `provided_visitor_hash_algorithm`. Для новых аккаунтов используется `hmac-sha512`. Также доступны `hmac-sha256`, `sha512`, `sha256` и `md5`; приватный ключ, если их несколько, может быть использован любой.

!!! Warning "Внимание!"
    Мы настоятельно **не рекомендуем** использовать алгоритм `md5`. Наиболее предпочтительным является алгоритм `hmac-sha512`.

Кодировка при вычислении `hash` должна быть либо `cp1251`, либо `koi8-r`, либо `utf-8`.

![Приватные ключи аккаунта](https://webim.ru/kb/img/dev/identification/id-2-0/private-keys-10-4.webp){ style="width: 1499px; max-width: 100%" }

Для вычисления хэша по алгоритму `HMAC-SHA256` строка вычисления должна выглядеть следующим образом:

```
hash = hmac.new(key=str(private_key), msg=msg, digestmod=hashlib.sha256).hexdigest()
```

где:

```
msg = 'Евгенийabc@webim.ru12345+781238553371481195621'
private_key = 'e64e35642555f3ecd64ae7dbb600dca8'
```

Или иначе:

```
hmac_sha256(display_name + email + id + phone + expires, "приватный ключ")
```

То есть:

```
hmac_sha256("Евгенийabc@webim.ru12345+781238553371481195621", "приватный ключ")
```

Пример кода для подсчёта хэша по алгоритму `HMAC-SHA256` (Java):

```
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Hex;

private String buildUserHash(final String userHashSrc, final String secretKey) {
  final Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
  final byte[] secretKeyBytes = secretKey.getBytes("US-ASCII");
  final SecretKeySpec secretKeySpec = new SecretKeySpec(secretKeyBytes, "HmacSHA256");

  sha256_HMAC.init(secretKeySpec);

  return Hex.encodeHexString(sha256_HMAC.doFinal(userHashSrc.getBytes("UTF-8")));
}
```

Пример кода для подсчёта хэша по алгоритму `HMAC-SHA256` (язык: Python 2 версии):

```
# -*- coding: utf-8 -*-

import hashlib
import hmac

private_key='e64e35642555f3ecd64ae7dbb600dca8'

encoding = 'utf-8'

fields = {'phone': u'+78123855337', 'display_name': u'Евгений', 'id': u'12345', 'email': u'abc@webim.ru'}

expires = 1481195621

msg_parts = []
for key in sorted(fields.keys()):
    value = fields[key]
    msg_parts.append(value.encode(encoding))

msg_parts.append(str(expires))
msg = ''.join(msg_parts)

hash_hmac = hmac.new(key=str(private_key), msg=msg, digestmod=hashlib.sha256).hexdigest()
```

Пример кода для подсчёта хэша по алгоритму `SHA256` (язык: Python 2 версии):

```
# -*- coding: utf-8 -*-

import hashlib
import hmac

private_key='e64e35642555f3ecd64ae7dbb600dca8'

encoding = 'utf-8'

fields = {'phone': u'+78123855337', 'display_name': u'Евгений', 'id': u'12345', 'email': u'abc@webim.ru'}

expires = 1481195621

msg_parts = []
for key in sorted(fields.keys()):
    value = fields[key]
    msg_parts.append(value.encode(encoding))

msg_parts.append(str(expires))
msg = ''.join(msg_parts)

hash_obj = hashlib.sha256()
hash_obj.update(msg)
hash_obj.update(private_key)
hash_sha = hash_obj.hexdigest().lower()
```
Пример кода для подсчёта хэша по алгоритму `sha-512` (язык: Python 2 версии):

```
# -*- coding: utf-8 -*-

import hashlib

private_key='e64e35642555f3ecd64ae7dbb600dca8'

encoding = 'utf-8'

fields = {'phone': u'+78123855337', 'display_name': u'Евгений', 'id': u'12345', 'email': u'abc@webim.ru'}

expires = 1481195621

msg_parts = []
for key in sorted(fields.keys()):
    value = fields[key]
    msg_parts.append(value.encode(encoding))

msg_parts.append(str(expires))
msg = ''.join(msg_parts)

hash_obj = hashlib.sha512()
hash_obj.update(msg.encode(encoding))
hash_obj.update(private_key.encode(encoding))
hash_sha = hash_obj.hexdigest().lower()
```

Для проверки контрольной суммы (хэша) вы также можете воспользоваться нашим **онлайн-калькулятором полей посетителя**, перейдя на [эту страницу](https://webim.ru/kb/dev/identification/visitor-fields-calculator.html).

## Приоритетность полей посетителя {: #visitor-fields-priority }

Информация (поля), идентифицирующая посетителя, может передаваться в одном или нескольких из следующих массивов данных:

  * `fields` — распознанная самим сервисом **Webim**

  * `provided_fields` — переданная фронтэндом (в случае авторизации посетителя)

  * `opFields` — [внесённая оператором в ходе диалога](https://webim.ru/kb/control-panel/sections.html#info-visitor)

При этом могут возникать ситуации, когда одни и те же поля передаются из разных источников и при этом не совпадают. Для того, чтобы набор полей о посетителе был единым и не имел противоречий, существует возможность определить приоритетность, на которую **Webim** будет ориентироваться. Приоритетность задаётся в параметре `visitor_fields_priority_order` настроек [account config](https://webim.ru/kb/for-admins/service-pages/account-config-editor.html): сначала указываются наиболее приоритетный массив полей, а далее менее приоритетные в порядке убывания. По умолчанию значением параметра является `["providedFields","fields","opFields"]`, что означает, что в случае передачи разных значений одного и того же поля (например, номера телефона посетителя) в нескольких множествах в единый набор полей о посетителе будет включено значение из `providedFields`, а остальные значения будут проигнорированы.

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

## Поля для маршрутизации { #chat-routing-fields }

Выбор размещения по правилам [маршрутизации посетителей](https://webim.ru/kb/for-admins/visitor-routing.html) выполняется на стороне виджета. Виджет видит поля из объекта `webim_visitor` и из отдельного объекта на странице:

```
window.chat_routing_fields = {
    subscription_type: 'premium',
    language: 'en'
};
```

Задайте объект до подключения скрипта виджета. Поля из `chat_routing_fields` не являются идентификацией посетителя: они не подписываются, не передаются методом `provide_visitor_fields` и не отображаются в карточке посетителя. Они нужны только для сопоставления с правилами маршрутизации.

Если объект `window.chat_routing_fields` задан в окне страницы с виджетом, при открытии чата в новой вкладке или в iframe его содержимое передаётся в окно чата параметром URL и там тоже доступно как `window.chat_routing_fields`.

Если одноимённое поле есть и в `webim_visitor.fields`, и в `chat_routing_fields`, для выбора размещения берётся значение из `chat_routing_fields`.

При [идентификации через токен](https://webim.ru/kb/dev/identification/authorization-scheme-tokenizer.html) объекта `webim_visitor` на странице нет, а поля из `provide_visitor_fields` виджету недоступны. В этом случае без `chat_routing_fields` правила маршрутизации не сработают.

## Идентификация по токену

Этот способ идентификации является взаимоисключающим с описанным выше. Для его реализации необходимо использовать метод `provide_visitor_fields` из [Webim Realtime API](https://webim.ru/kb/dev/api/realtime-2.0.html). Также функциональность метода доступна в тех случаях, когда виджет чата для посетителей расположен внутри iframe.

Маршрутизация посетителей при идентификации по токену настраивается через `window.chat_routing_fields` — см. [поля для маршрутизации](#chat-routing-fields).

## Идентификация клиентов в мобильных приложениях

Если Вы используете **Webim Mobile SDK** для **iOS** или **Android**, то для идентификации клиентов Вы можете передать объект данных в формате JSON в SDK. Подробнее читайте в документации:

[Документация iOS Mobile SDK](https://webim.ru/kb/mobile/sdk/v-3-0/ios-sdk-handbook.html)

[Документация Android Mobile SDK](https://webim.ru/kb/mobile/sdk/v-3-0/android-sdk-handbook.html)

## Идентификация при использовании ссылки на visitor/chat

Для корректного отображения заголовка и ссылки страницы, с которого открыли ссылку чата, в интерфейсе оператора можно передать через GET параметр `start-page`, как значение в формате JSON с полями `title` и `url`, например:

```
{
    "title": "Главная страница",
    "url": "https://example.com"
}
```

## Возможные ошибки аутентификации

| Ошибка                                 | Описание                                                                                                                                                                                 |
|----------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `provided-visitor-expired`             | Истёк срок валидности предоставленных в `webim_visitor` данных                                                                                                                           |
| `wrong-provided-visitor-expires-value` | Неверное значение поля `expires`. Ошибка вызывается при несоответствии значения типу данных `Int` или при слишком большом значении поля.                                                 |
| `wrong-provided-visitor-field-value`   | Неверное значение одного из полей посетителя. Ошибка вызывается при несоответствии значения типу данных `String`                                                                         |
| `wrong-provided-visitor-hash-value`    | Неверное значение контрольной суммы полей посетителя, в т.ч. пустое или отсутствующее поле.                                                                                              |
| `provided-auth-token-not-found`        | Ошибка может возникнуть при авторизации по токену. Предоставленный токен не найден в системе. Подробнее об авторизации по токену можно прочитать в [этой статье](https://webim.ru/kb/dev/api/realtime-2.0.html) |

[Старая версия идентификации посетителей](https://webim.ru/kb/dev/identification/id-1-0.html)

---

Источник: https://webim.ru/kb/dev/identification/id-2-0.html
