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

Перейти к концу метаданных
Переход к началу метаданных

Вы просматриваете старую версию данной страницы. Смотрите текущую версию.

Сравнить с текущим просмотр истории страницы

« Предыдущий Версия 30 Текущий »

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

Алгоритм

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Обрати внимание, в тот момент, когда мобильное устройство делает первый запрос на сервер, пользователь еще не авторизовался в базе данных. Чтобы все-таки как-то получить ответ от сервера 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""","");
	Возврат Результат; 	
КонецФункции

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

  • Нет меток