Здесь ты найдешь описание механизма упрощенной авторизации по СМС и весь необходимый исходный код
Алгоритм
Пользователь при запуске приложения вводит номер своего телефона и нажимает Получить СМС
Мобильное приложение отправляет http-запрос на сервер с уведомлением, что пользователь хочет авторизоваться
Сервер проверяет:
Сервер, если условия выполняются, отправляет одноразовый код пользователю через оператора отправки СМС
Сервер, если условия не выполняются, отправляет ошибку Пользователю
Пользователь вводит одноразовый код из СМС
Мобильное приложение отправляет http-запрос на сервер с уведомлением, что пользователь авторизовался
Сервер формирует начальные данные и регистрирует их на узле пользователя
Дополнительные настройки
Обрати внимание, в тот момент, когда мобильное устройство делает первый запрос на сервер, пользователь еще не авторизовался в базе данных. Чтобы все-таки как-то получить ответ от сервера 1С, я создаю специальный веб-сервер для авторизации. Здесь я описала, как его правильно настроить: Настройка веб-сервера для авторизации
Код
Пользователь нажал получить код авторизации в мобильном устройстве
Мобильное приложение. Получить код авторизации
&НаКлиенте
Процедура ПолучитьКодАвторизации(Команда)
Если Не ЗначениеЗаполнено(КодСтраны) Тогда
Сообщить("Не выбран код страны");
Возврат;
КонецЕсли;
Если Не ЗначениеЗаполнено(НомерТелефона) Тогда
Сообщить("Не заполнен номер телефона");
Возврат;
КонецЕсли;
Если СтрДлина(Формат(НомерТелефона, "ЧГ=")) <> 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";
НовыйУзел.Наименование = "Центральный";
НовыйУзел.Записать();
ЦентральныйУзелОбмена = НовыйУзел.Ссылка;
КонецЕсли;
Узел = ПланыОбмена.РВ_СправедливыйНаблюдатель.ЭтотУзел();
Если НЕ ЗначениеЗаполнено(Узел.Код) ИЛИ Узел.Код <> КодМобильногоУстройства Тогда
ОбъектУзла = Узел.ПолучитьОбъект();
ОбъектУзла.Код = КодМобильногоУстройства;
ОбъектУзла.Наименование = Пользователь;
ОбъектУзла.Записать();
КонецЕсли;
Возврат ЦентральныйУзелОбмена;
КонецФункции
После успешной авторизации запускается регистрация начальных данных для данного пользователя. Я отправляю только те данные (записи справочников, регистров), которые точно понадобятся пользователю. Остальные данные можно отправить позднее
Сервер. Регистрация начальных данных на узле авторизованного пользователя
Функция GetInitialData(Запрос)
УстановитьПривилегированныйРежим(Истина);
Попытка
КодМобильногоУстройства = Запрос.ПараметрыURL.Получить("КодМобильногоУстройства");
ИмяПользователя = Запрос.ПараметрыURL.Получить("ИмяПользователя");
МобильнаяОС = Перечисления.РВ_МобильнаяОС.ПустаяСсылка();
Для Каждого ТекПараметр ИЗ Запрос.ПараметрыЗапроса Цикл
Если ВРег(ТекПараметр.Ключ) = ВРег("MobileOS") Тогда
МобильнаяОС = Перечисления.РВ_МобильнаяОС[ТекПараметр.Значение];
КонецЕсли;
КонецЦикла;
УзелОбмена = ИнициализацияУзлаОбмена("РВ_СправедливыйНаблюдатель", Справочники.РВ_МобильноеПриложение.СправедливыйНаблюдатель, КодМобильногоУстройства, ИмяПользователя, МобильнаяОС);
ОтветНаблюдателю = ОтдатьНачальныеДанныеСправедливомуНаблюдателю(УзелОбмена, КодМобильногоУстройства, ИмяПользователя);
Ответ = Новый HTTPСервисОтвет(200);
Ответ.УстановитьТелоИзСтроки(ОтветНаблюдателю);
Исключение
Ответ = Новый HTTPСервисОтвет(400);
Ответ.УстановитьТелоИзСтроки(ОписаниеОшибки());
КонецПопытки;
Возврат Ответ;
КонецФункции
Функция ИнициализацияУзлаОбмена(ИмяПланаОбмена, МобильноеПриложение, КодУстройства, ИмяПользователя, МобильнаяОС) Экспорт
УстановитьПривилегированныйРежим(Истина);
УзелОбмена = ПланыОбмена[ИмяПланаОбмена].НайтиПоКоду(КодУстройства);
ПользовательИБ = ПользователиИнформационнойБазы.НайтиПоИмени(ИмяПользователя);
Если ПользовательИБ = Неопределено Тогда
Пользователь = Неопределено;
Иначе
Пользователь = Справочники.Пользователи.НайтиПоРеквизиту("ИдентификаторПользователяИБ", ПользовательИБ.УникальныйИдентификатор);
КонецЕсли;
Если УзелОбмена.Пустая() Тогда
НовыйУзел = ПланыОбмена[ИмяПланаОбмена].СоздатьУзел();
НовыйУзел.Код = КодУстройства;
НовыйУзел.Наименование = ИмяПользователя;
Если ЗначениеЗаполнено(МобильнаяОС) Тогда
НовыйУзел.МобильнаяОС = МобильнаяОС;
КонецЕсли;
НовыйУзел.Пользователь = Пользователь;
НовыйУзел.ДатаСоздания = ТекущаяДата();
НовыйУзел.ОбменДанными.Загрузка = Истина;
НовыйУзел.Записать();
УзелОбмена = НовыйУзел.Ссылка;
ИначеЕсли УзелОбмена.Наименование <> ИмяПользователя ИЛИ УзелОбмена.Пользователь <> Пользователь Тогда
ОбъектУзла = УзелОбмена.ПолучитьОбъект();
ОбъектУзла.Наименование = ИмяПользователя;
ОбъектУзла.Пользователь = Пользователь;
ОбъектУзла.ДатаСоздания = ТекущаяДата();
ОбъектУзла.Записать();
ПланыОбмена.УдалитьРегистрациюИзменений(УзелОбмена);
КонецЕсли;
Возврат УзелОбмена;
КонецФункции
Функция ОтдатьНачальныеДанныеСправедливомуНаблюдателю(Знач УзелОбмена, КодУстройства, ИмяПользователя)
УстановитьПривилегированныйРежим(Истина);
ПользовательИБ = ПользователиИнформационнойБазы.НайтиПоИмени(ИмяПользователя);
Если ПользовательИБ = Неопределено Тогда
Возврат "no";
КонецЕсли;
ИмяXDTOПакета = "RV_FairObserver";
ЗаписьХМЛ = Новый ЗаписьXML;
ЗаписьХМЛ.УстановитьСтроку();
ЗаписьСообщения = ПланыОбмена.СоздатьЗаписьСообщения();
ЗаписьСообщения.НачатьЗапись(ЗаписьХМЛ, УзелОбмена);
//Здесь в сообщение записываются начальные данные
ЗаписьСообщения.ЗакончитьЗапись();
Результат = ЗаписьХМЛ.Закрыть();
Результат = СтрЗаменить(Результат, " xmlns=""" + ИмяXDTOПакета + """ xmlns:xs=""http://www.w3.org/2001/XMLSchema"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance""","");
Возврат Результат;
КонецФункции
Полезные ссылки
Добавить комментарий