Единый семинар «1С» для бухгалтеров и руководителей

Google OAuth и мобильное приложение

Обмен

Об аутентификации для работы с сервисами google из мобильного или настольного приложения

Вступление

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

Здесь описано много разных способов и для устанавливаемых приложений рекомендуется использовать библиотеки, но, к сожалению, не в нашем случае. Возможно, есть способ как-то срастить библиотеку и 1С с помощью внешней компоненты, но у меня не хватило терпения осилить его. Также имеется ручной способ аутентификации - это когда пользователь разрешает доступ и копирует-вставляет токен обновления (refresh_token) из браузера в приложение. Этот способ самый простой и на нём можно было бы остановиться, но мы не ищем простых путей и в данной публикации речь пойдет о способе аутентификации через промежуточный шлюз, подкрепленный примерами. Способ универсален и будет работать в настольной версии.

Подготовка

Для начала в консоли необходимо создать проект и учетные данные "Идентификатор клиента OAuth" (веб-приложение). В поле "Разрешенные URI перенаправления" указать адреса шлюза (например, localhost/addcode/auth) на которые будет отвечать сервер google (конечный запрос будет иметь вид: localhost/addcode/auth?code=1&state=2&scope=3 или localhost/addcode/auth?state=1&error=2).  Этого будет достаточно, но для работы с каким-либо сервисом необходимо включить соответствующий api, создать ключ приложения... Об этом не буду писать, так как в интернете всё подробно расписано. В конце необходимо скачать из консоли json файл с учетными данными.

Далее потребуется веб-сервер (шлюз), где будут реализованы http-сервисы. Их можно сделать как на 1С, так и на другом, более универсальном, языке. Также шлюз физически может располагаться как в локальной сети, так и на хостинге в интернете. Я же выбрал вариант с бесплатным хостингом, где поддерживается php и mysql.

В общий макет УчетныеДанныеGoogle необходимо загрузить скачанный ранее json файл.

Реализация

Процедура аутентификации начинается с клиентской части:

&НаКлиенте
Процедура Войти(Команда)
	стрКлюч = Строка(Новый УникальныйИдентификатор);
	ДанныеДляВхода = СервисыGoogleКлиентСервер.ДанныеВходаВАккаунт();
	УчетныеДанные = ДанныеДляВхода.УчетныеДанные["web"]; 
	
	ШаблонЗапроса = ДанныеДляВхода.ШаблонЗапроса;
	ТекстЗапроса = СтрШаблон(ШаблонЗапроса, 
						УчетныеДанные["auth_uri"], 
						УчетныеДанные["client_id"], 
						УчетныеДанные["redirect_uris"][0], 
						ДанныеДляВхода.ОбластиДоступа, стрКлюч);
	
	ЗапуститьПриложение(ТекстЗапроса);
	
	ПодключитьОбработчикОжидания("ПолучитьКод", 3, Ложь);
КонецПроцедуры

Здесь формируется текст http-запроса, запускается браузер и подключается обработчик ожидания, который опрашивает шлюз. Переменная стрКлюч необходима для идентификации, по ней будем находить кому что принадлежит. В redirect_uris адреса, которые были указаны при создании учетных данных OAuth в консоли. По этим адресам будет перенаправлять сервер google после ответа пользователя. Нам же необходимо обработать ответ и вывести пользователю результат (успешно...).

Файл index.php

<?php
$servername = "";
$username = "";
$password = "";
$dbname = "";

$setData = false;
if(isset($_GET["error"]) && !empty($_GET["error"])){
	$state = $_GET["state"];
	$code = "";
	$error = $_GET["error"];
        $scope = "";
	$setData = true;
}elseif(!empty($_GET)){
	$state = $_GET["state"];
	$code = $_GET["code"];
	$error = "";
        $scope = $_GET["scope"];
	$setData = true;
}

if($setData){
	
	$conn = new mysqli($servername, $username, $password, $dbname);
	if ($conn->connect_error) {
		die("Connection failed: " . $conn->connect_error);
	}
	
	$sql = "INSERT INTO tCodes (state, code, error, scope) VALUES ('$state', '$code', '$error', '$scope')";
		
	if ($conn->query($sql) === TRUE) {
		echo "Код получен";
	} else {
		echo "Error: " . $sql . "<br>" . $conn->error;
	}
	$conn->close();
}
?>

Код получает значения параметров из запроса и записывает их в базу данных. При использовании такого же способа предварительно нужно создать базу данных и таблицу. Значение параметра state - это стрКлюч, code - код для получения токенов, scope - область доступа. В php не силен, но код рабочий, собирал копипастой из интернета как черновик, а для рабочих систем можно сделать лучше.

Всё это время 1С опрашивает шлюз с ключом и как только ответ будет получен обработчик отключается.

Обработчик ожидания ПолучитьКод:

&НаКлиенте
Процедура ПолучитьКод() Экспорт
	
	АдресШлюза = "";
	ТекстЗапроса = "?state=" + стрКлюч;
		
	Запрос = Новый HTTPЗапрос(ТекстЗапроса);
	Соединение = Новый HTTPСоединение(АдресШлюза,,,,,, Новый ЗащищенноеСоединениеOpenSSL);
	Ответ = Соединение.Получить(Запрос);
	стрОтвет = Ответ.ПолучитьТелоКакСтроку();
	
	РезультатЧтения = ОбщегоНазначенияКлиентСервер.ПеревестиJsonВОбъект(стрОтвет);
	Если РезультатЧтения["state"] = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	ОтключитьОбработчикОжидания("ПолучитьКод");
	// Далее механизм обмена кода на токен обновления и токен доступа

КонецПроцедуры

В процедуре нужно указать адрес своего шлюза (например, localhost/addcode/auth/res.php), где реализована обработка и передача данных.

Файл res.php

<?php
$servername = "";
$username = "";
$password = "";
$dbname = "";

$state= $_GET['state'];

// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
	die("Connection failed: " . $conn->connect_error);
}

$sql = "SELECT state, code, error, scope FROM tCodes WHERE state = '$state'";
$result = $conn->query($sql);

if ($result->num_rows == 1) {
	$row = $result->fetch_assoc();
	$data = [ 'state' => $row["state"], 'code' => $row["code"], 'scope' => $row["scope"], 'error' => $row["error"]];
        echo json_encode( $data );
	
	$sql = "DELETE FROM tCodes WHERE state = '$state'";
	$conn->query($sql);
} else {
    $data = [ 'error' => 'not_found' ];
    http_response_code(404);
    echo json_encode( $data );
}

$conn->close();
?>

Запрос получает данные по ключу и возвращает в виде json. Этот код тоже рабочий черновик.

Далее значение параметра code нужно обменять на токены (продолжение процедуры ПолучитьКод).

	Код = РезультатЧтения["code"];
	ДанныеОбменаКодаНаТокен = СервисыGoogleКлиентСервер.ДанныеОбменаКодаНаТокен(стрКлюч);
	УчетныеДанные = ДанныеОбменаКодаНаТокен.УчетныеДанные["web"];
	ШаблонЗапроса = ДанныеОбменаКодаНаТокен.ШаблонЗапроса;
	ТекстЗапроса = СтрШаблон(ШаблонЗапроса, Код, УчетныеДанные["client_id"], УчетныеДанные["client_secret"], УчетныеДанные["redirect_uris"][0]);
	
	Запрос = Новый HTTPЗапрос(ДанныеОбменаКодаНаТокен.АдресРесурса);
	Запрос.Заголовки = ДанныеОбменаКодаНаТокен.Заголовки;
	Запрос.УстановитьТелоИзСтроки(ТекстЗапроса);
	
	Соединение = Новый HTTPСоединение(ДанныеОбменаКодаНаТокен.АдресСервера,,,,, 10, Новый ЗащищенноеСоединениеOpenSSL);
	Ответ = Соединение.ОтправитьДляОбработки(Запрос);
	стрОтвет = Ответ.ПолучитьТелоКакСтроку();
	Если Ответ.КодСостояния = 200 Тогда
		РезультатЧтения = ОбщегоНазначенияКлиентСервер.ПеревестиJsonВОбъект(стрОтвет);
		стрТокенОбновления = РезультатЧтения["refresh_token"];
		стрТокенДоступа = РезультатЧтения["access_token"];
		
		Если ЗначениеЗаполнено(стрТокенОбновления) Тогда
			УстановитьТокенОбновления(стрТокенОбновления);
		КонецЕсли;
	КонецЕсли;
	
	стрРезультат = стрОтвет;

Итог

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

Инициируем процедуру входа.

Открывается браузер, пользователь выбирает аккаунт и разрешает или отклоняет запрос.

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

Приложение всё это время опрашивает шлюз и обменивает код на токены.

Проверяем запросом данных пользователя.

В архиве конфигурация и файлы шлюза.

Скачать файлы

Наименование Файл Версия Размер
Конфигурация + файлы шлюза
.zip 11,80Kb
03.10.17
4
.zip 11,80Kb 4 Скачать

См. также

В этой теме еще нет сообщений.
Оставьте свое сообщение