ООО "Рассвет" для Infostart Event 2021

Авторизация

Здесь ты найдешь описание механизма упрощенной авторизации по СМС и весь необходимый исходный код

Настройка web-сервера

Обрати внимание, в тот момент, когда мобильное устройство делает первый запрос на сервер, пользователь еще не авторизовался в базе данных. Чтобы все-таки как-то получить ответ от сервера 1С, я создаю специальный веб-сервер для авторизации. Здесь я описала, как его правильно настроить: Настройка веб-сервера для авторизации

Алгоритм

  • Администратор регистрирует пользователя в информационной базе, указывая его мобильный номер

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

  • Пользователь при запуске приложения вводит номер своего телефона и нажимает Получить СМС

  • Мобильное приложение отправляет http-запрос на сервер с уведомлением, что пользователь хочет авторизоваться

  • Сервер проверяет:

    • Наличие пользователя по номеру телефона

    • Пользователь является наблюдателем

  • Сервер, если условия выполняются, отправляет одноразовый код пользователю через оператора отправки СМС

  • Сервер, если условия не выполняются, отправляет ошибку Пользователю

  • Пользователь вводит одноразовый код из СМС

  • Мобильное приложение отправляет http-запрос на сервер с уведомлением, что пользователь авторизовался

  • Сервер формирует начальные данные и регистрирует их на узле пользователя

Данный метод не является безопасным и должен применяться только там, где действительно необходимо. Всегда используй https-соединение с web-сервером! SSL-сертификат стоит не так дорого, чтобы потом не кусать локти

Код

Пользователь нажал получить код авторизации в мобильном устройстве

&НаКлиенте Процедура ПолучитьКодАвторизации(Команда) Если Не ЗначениеЗаполнено(КодСтраны) Тогда Сообщить("Не выбран код страны"); Возврат; КонецЕсли; Если Не ЗначениеЗаполнено(НомерТелефона) Тогда Сообщить("Не заполнен номер телефона"); Возврат; КонецЕсли; Если СтрДлина(Формат(НомерТелефона, "ЧГ=")) <> 10 Тогда Сообщить("Номер телефона указан неверно. Необходимо ввести 10 цифр"); Возврат; КонецЕсли; ОдноразовыйКод = 0; ОдноразовыйКодИзСообщения = 0; ЛогинИзСообщения = ""; ПарольИзСообщения = ""; СтруктураВозврата = ОтправитьСМСНаАвторизацию(); Если СтруктураВозврата.КодСостояния = 200 Тогда тЧтение = Новый ЧтениеJSON; тЧтение.УстановитьСтроку(СтруктураВозврата.ОтветСтрока); ДанныеОтвета = ПрочитатьJSON(тЧтение); тЧтение.Закрыть(); ОдноразовыйКодИзСообщения = ДанныеОтвета.Code; ЛогинИзСообщения = ДанныеОтвета.Login; ПарольИзСообщения = ДанныеОтвета.Pass; Элементы.ОдноразовыйКод.Видимость = Истина; Элементы.ПолучитьКодАвторизации.Доступность = Ложь; ОсталосьДоПовторнойОтправки = 60; Элементы.ПолучитьКодАвторизации.Заголовок = "Получить повторный код можно через"; Элементы.ОсталосьДоПовторнойОтправки.Видимость = Истина; ПодключитьОбработчикОжидания("ОтсчетВремени", 1, Ложь); Сообщить("Код авторизации отправлен на указанный номер"); Иначе Сообщить(СтруктураВозврата.ОтветСтрока); Элементы.ОдноразовыйКод.Видимость = Ложь; Элементы.ПолучитьКодАвторизации.Доступность = Истина; Элементы.ПолучитьКодАвторизации.Заголовок = "Отправить SMS с кодом"; КонецЕсли; КонецПроцедуры &НаСервере Функция ОтправитьСМСНаАвторизацию() Запрос = Новый HTTPЗапрос; Запрос.АдресРесурса = СокрЛП(Константы.ИмяБазы.Получить()) + "/hs/RassvetAuthorizationSMS/" + Формат(НомерТелефона, "ЧГ=") + "?CountryCode=" + СтрЗаменить(КодСтраны, "+", ""); Соединение = Новый HTTPСоединение(Константы.IPСервера.Получить(),,,,,, Новый ЗащищенноеСоединениеOpenSSL); Ответ = Соединение.Получить(Запрос); Возврат Новый Структура("КодСостояния, ОтветСтрока", Ответ.КодСостояния, Ответ.ПолучитьТелоКакСтроку()); КонецФункции

 

Формирование одноразового кода на сервере и отправка его на мобильное устройство по СМС. Параллельно в мобильное устройство возвращается этот же код.

Функция RassvetAuthorizationSMSGet(Запрос) Ответ = Новый HTTPСервисОтвет(200); НомерТелефона = Запрос.ПараметрыURL.Получить("НомерТелефона"); КодСтраны = ""; Для Каждого ТекПараметр ИЗ Запрос.ПараметрыЗапроса Цикл Если ВРег(ТекПараметр.Ключ) = ВРег("CountryCode") Тогда КодСтраны = ТекПараметр.Значение; КонецЕсли; КонецЦикла; Если НЕ ЗначениеЗаполнено(КодСтраны) Тогда КодСтраны = "7"; КонецЕсли; СтруктураВозврата = НайтиПользователяПоНомеруТелефона(КодСтраны, НомерТелефона); Если СтруктураВозврата.Пользователь = Неопределено Тогда Ответ.КодСостояния = 405; Результат = СтруктураВозврата.Ошибка; Иначе ОшибкаДоступаКПриложению = ПроверитьДоступПользователяПоМобильномуПриложению(СтруктураВозврата.Пользователь); Если ЗначениеЗаполнено(ОшибкаДоступаКПриложению) Тогда Ответ.КодСостояния = 405; Результат = ОшибкаДоступаКПриложению; Иначе СтруктураВозвратаОтправкиСМС = ОтправитьСообщениеПоСМС(СтруктураВозврата.Логин, СтруктураВозврата.Пароль, КодСтраны, НомерТелефона); Если СтруктураВозвратаОтправкиСМС.Ошибка Тогда Ответ.КодСостояния = 405; КонецЕсли; Результат = СтруктураВозвратаОтправкиСМС.ТекстСообщения; КонецЕсли; КонецЕсли; Ответ.УстановитьТелоИзСтроки(Результат, КодировкаТекста.UTF8); Возврат Ответ; КонецФункции Функция НайтиПользователяПоНомеруТелефона(КодСтраны, НомерТелефона) УстановитьПривилегированныйРежим(Истина); СтруктураВозврата = Новый Структура("Пользователь, Логин, Пароль, Ошибка"); // Здесь код поиска пользователя по номеру телефона. У каждой конфигурации поиск свой Возврат СтруктураВозврата; КонецФункции Функция ПроверитьДоступПользователяПоМобильномуПриложению(Пользователь, МобильноеПриложение) Экспорт УстановитьПривилегированныйРежим(Истина); ФизическоеЛицо = Пользователь.ФизЛицо; Если НЕ ЗначениеЗаполнено(ФизическоеЛицо) Тогда Возврат "У пользователя не указано Физическое лицо. Обратитесь к руководителю."; КонецЕсли; //Здесь код проверки доступа пользователя. У каждой конфигурации своя проверка Возврат ""; КонецФункции Функция ОтправитьСообщениеПоСМС(Логин, Пароль, КодСтраны, НомерТелефона) СтруктураВозврата = Новый Структура("Ошибка, ТекстСообщения"); УстановитьПривилегированныйРежим(Истина); ГСЧ = Новый ГенераторСлучайныхЧисел(ТекущаяУниверсальнаяДатаВМиллисекундах()); СлучайнаяСтрока = ""; СлучайнаяСтрока = СлучайнаяСтрока + Формат(ГСЧ.СлучайноеЧисло(1,9), "ЧГ="); СлучайнаяСтрока = СлучайнаяСтрока + Формат(ГСЧ.СлучайноеЧисло(0,9), "ЧГ="); СлучайнаяСтрока = СлучайнаяСтрока + Формат(ГСЧ.СлучайноеЧисло(0,9), "ЧГ="); СлучайнаяСтрока = СлучайнаяСтрока + Формат(ГСЧ.СлучайноеЧисло(0,9), "ЧГ="); СлучайноеЧисло = Число(СлучайнаяСтрока); ЗаписьJSON = Новый ЗаписьJSON; ЗаписьJSON.УстановитьСтроку(); Данные = Новый Структура("Code, Login, Pass", СлучайноеЧисло, Логин, Пароль); ЗаписатьJSON(ЗаписьJSON, Данные, Новый НастройкиСериализацииJSON); СтруктураПароля = ЗаписьJSON.Закрыть(); ТекстСМС = "Код авторизации: " + СлучайнаяСтрока; МассивПолучателей = Новый Массив(); МассивПолучателей.Добавить("+" + КодСтраны + НомерТелефона); Результат = ОтправкаSMS.ОтправитьSMS(МассивПолучателей, ТекстСМС, "Рассвет", Ложь); //Функция БСП Если ЗначениеЗаполнено(Результат.ОписаниеОшибки) Тогда СтруктураВозврата.Ошибка = Истина; СтруктураВозврата.ТекстСообщения = Результат.ОписаниеОшибки; Иначе СтруктураВозврата.Ошибка = Ложь; СтруктураВозврата.ТекстСообщения = СтруктураПароля; КонецЕсли; Возврат СтруктураВозврата; КонецФункции

После ввода кода пользователем происходит его сверка с тем, что прислал сервер. Если коды совпали - происходит авторизация.

&НаКлиенте Процедура ОдноразовыйКодПриИзменении(Элемент) Если ОдноразовыйКод = 0 Тогда Возврат; КонецЕсли; Если ОдноразовыйКод <> ОдноразовыйКодИзСообщения Тогда Сообщить("Коды не совпадают"); Возврат; КонецЕсли; Пользователь = ЛогинИзСообщения; Пароль = ПарольИзСообщения; ОК(Неопределено); КонецПроцедуры &НаКлиенте Процедура ОК(Команда) Ответ = ПроверитьЛогинИПароль(Пользователь, Пароль); Если Ответ = Истина Тогда ОбщийКлиент.УстановитьIDУстройства(); Оповестить("АвторизацияПрошлаУспешно"); Закрыть(Истина); Иначе ОбменСервер.ДобавитьОшибкуВРегистр(Ответ, ПредопределенноеЗначение("Перечисление.ТипПротоколаСобытий.Ошибка")); Сообщить("Неправильный логин или пароль"); КонецЕсли; КонецПроцедуры &НаСервере Функция ПроверитьЛогинИПароль(Пользователь, Пароль) Экспорт УстановитьПривилегированныйРежим(Истина); Попытка КодМобильногоУстройства = ОбщийСервер.ПолучитьКодМобильногоУстройства(); Запрос = Новый HTTPЗапрос; АдресРесурса = СокрЛП(Константы.ИмяБазы.Получить()) + "/hs/ObmenHTTPFairObserver/GetInitialData/" + КодМобильногоУстройства + "/" + Пользователь; Если ЗначениеЗаполнено(Константы.МобильнаяОС.Получить()) Тогда АдресРесурса = АдресРесурса + "?MobileOS=" + Строка(Константы.МобильнаяОС.Получить()); КонецЕсли; Запрос.АдресРесурса = АдресРесурса; Соединение = Новый HTTPСоединение(Константы.IPСервера.Получить(),,Пользователь, Пароль,,, Новый ЗащищенноеСоединениеOpenSSL); Ответ = Соединение.Получить(Запрос); Если Ответ.КодСостояния = 401 Тогда Возврат "Неправильный логин или пароль"; ИначеЕсли Ответ.КодСостояния = 200 Тогда УстановитьПривилегированныйРежим(Истина); ЦентральныйУзелОбмена = ИнициализацияОбмена(Пользователь, КодМобильногоУстройства); ДанныеОбменаXML = Ответ.ПолучитьТелоКакСтроку(); ЧтениеXML = Новый ЧтениеXML; ЧтениеXML.УстановитьСтроку(ДанныеОбменаXML); ЧтениеСообщения = ПланыОбмена.СоздатьЧтениеСообщения(); ЧтениеСообщения.НачатьЧтение(ЧтениеXML, ДопустимыйНомерСообщения.Любой); Пока ВозможностьЧтенияXML(ЧтениеXML) Цикл Данные = ПрочитатьXML(ЧтениеXML); Если НЕ Данные = Неопределено Тогда Данные.ОбменДанными.Загрузка = Истина; Данные.Записать(); КонецЕсли; КонецЦикла; ЧтениеСообщения.ЗакончитьЧтение(); ЧтениеXML.Закрыть(); Константы.ИмяПользователя.Установить(Пользователь); Константы.Пароль.Установить(Пароль); Возврат Истина; Иначе Возврат Ответ.ПолучитьТелоКакСтроку(); КонецЕсли; Исключение Возврат ОписаниеОшибки(); КонецПопытки; КонецФункции &НаСервере Функция ИнициализацияОбмена(Пользователь, КодМобильногоУстройства) Экспорт УстановитьПривилегированныйРежим(Истина); ЦентральныйУзелОбмена = ПланыОбмена.РВ_СправедливыйНаблюдатель.НайтиПоКоду("001"); Если ЦентральныйУзелОбмена.Пустая() Тогда НовыйУзел = ПланыОбмена.РВ_СправедливыйНаблюдатель.СоздатьУзел(); НовыйУзел.Код = "001"; НовыйУзел.Наименование = "Центральный"; НовыйУзел.Записать(); ЦентральныйУзелОбмена = НовыйУзел.Ссылка; КонецЕсли; Узел = ПланыОбмена.РВ_СправедливыйНаблюдатель.ЭтотУзел(); Если НЕ ЗначениеЗаполнено(Узел.Код) ИЛИ Узел.Код <> КодМобильногоУстройства Тогда ОбъектУзла = Узел.ПолучитьОбъект(); ОбъектУзла.Код = КодМобильногоУстройства; ОбъектУзла.Наименование = Пользователь; ОбъектУзла.Записать(); КонецЕсли; Возврат ЦентральныйУзелОбмена; КонецФункции

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

Полезные ссылки

ООО "Рассвет" для Infostart Event 2021