Каталог решений - Когда хотим знать IP клиента…

Когда хотим знать IP клиента…

Когда хотим знать IP клиента…

В наличии

В процессе разработки web приложения на 1С, и это не шутка))), а пожелание заказчика, возникла ситуации когда понадобилось знать, с какого IP подключался клиент.

Категория:

Описание

Не судите строго, пишу первый раз. Хотя и были попытки до этого, но так не разу не опубликовал.

И так есть самописная конфигурация на Платформе 8.3 с кусками БСП, в ней реализован некий web сервис для клиентов компании.

В web сервисе есть графический интерфейс для работы из браузера и rest api.

Была поставлена задача определять IP адрес клиента в независимости от того как он подключился к сервису.

Помогли в решении эти посты:

//sale.itcity.ru/public/1159393/

//sale.itcity.ru/public/1157609/

//sale.itcity.ru/public/338126/

И так у нас два варианта подключения. Начнем пожалуй с самого простого и быстрого получить IP при подключении через REST API.

Клиент получает данные через HTTP запросы, обращается к 1С базе через web сервер Apache.

Apache знает IP клиента, и мы можем поместить это адрес в некую переменную.

Для этого нам нужно:

в файле конфигурации Apache раскомментировать строки

#LoadModule headers_module modules/mod_headers.so
#LoadModule ssl_module modules/mod_ssl.so

добавить строки

# Проброс ip адреса клиента для http-сервисов 1С в заголовке client_ip_addr
RequestHeader append client_ip_addr "%{REMOTE_ADDR}s"

во все вызовы HTTP методов в базе 1С внедрить код, получающий ip клиента от Apache. В нашем случаи мы делаем так. Главное это как видите получения IP изи Заголовка http запроса.

Попытка
     ipКлиентаОпределен = ПараметрыСеанса.IpКлиента;
Исключение
     ПараметрыСеанса.IpКлиента = Запрос.Заголовки.Получить("client_ip_addr");
КонецПопытки;

И мы сохраняем в параметры сеанса, так как пока сеанс жив то нет смысла обновлять IP.

С эти всё оказалось просто. Но есть второй случай когда клиент не использует REST API, а заходит через web клиент.

Как узнать внешний IP клиента?

Мы решили так, пусть клиент сам нам скажет свой IP.

Но просить его писать это в поле ещё и смотреть в интернете было бы странно.

Значить это должно сделать за него 1С.

Решение приведенное ниже не является красивым, и работает не во всех 100% случаев (об этом ниже).

Клиент 1С сам по себе не имеет информации о настройках сетевой карты машины, на которой он исполняется, и даже если получит эту информацию — она может ничего не сказать о внешнем ip-адресе.
Очевидным решением является "спросить" у общедоступных сервисов наш ip-адрес с использованием HTTP-подключения например к ресурсу https://json.geoiplookup.io/api.
Но это невозможно сделать для web-клиента, т.к. методы работы с HTTP недоступны на web-клиенте

Значит нужно какое-то другое решение, и таким решением будет отображение поля HTML документа с js, а из js можно вызвать get https://json.geoiplookup.io/api.
Нюанс: просто создать HTML-документ недостаточно: js внутри него не отработает, также просто создать и не отображать форму не выйдет — js в поле HTTP-документа запускается только при отображении, в этом и состоит "некрасивость" решения — пользователю придется лицезреть запуск этой формы.

Если сделать пару допущений, то станет ясно, что все не так плохо:

Допущение №1 — скорость выполнения обработки достаточно высокая, чтобы пользователь ее не заметил В толстом и тонком клиенте выполнение такой обработки будет почти мгновенным и пользователем (вероятно) останется незамеченным. Что же до web-клиента? там все медленно!

Допущение №2 — такую обработку имеет смысл запускать при старте приложения и в этот момент можно ее чем-нибудь прикрыть Можно запустить свое лого на web-страничке во время загрузки web-клиента и отображения окна обработки.

 

  • Первое что понадобится — место где мы будем хранить полученную информацию, в нашем случае это параметр сеанса IpКлиента.
  • Второе — сама обработка
    Создаем обработку, и форму в ней (на самом деле подойдет любой вид форм).
    На форму добавляем строковый реквизит "HTMLДокумент", в элементах задаем ему вид Поле HTML документа
    и целочисленный реквизит "ПопытокПолученияIPСделано", он будет хранить информацию о том как долго длится попытка получения ip-адреса.
    Код модуля формы:

 

&НаКлиенте
Процедура ПриОткрытии(Отказ)
	Попытка
		// синхронный запрос GET
		HTMLДокумент = "
		|<!DOCTYPE html>
		|<html>
		|	<head>
		|		<meta charset='UTF-8'>
		|		<script src='http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js' type='text/javascript'></script>
		|	</head>
		|	<body></body>
		|	<script>
		|		function httpGet(theUrl) {
		|			var xmlHttp = new XMLHttpRequest();
		|			xmlHttp.open( 'GET', theUrl, false ); // false for synchronous request
		|			xmlHttp.send( null );
		|			return xmlHttp.responseText;
		|		}
		|		
		|		getIp = function() {
		|			try {
		|				responseText = httpGet('https://api.ipify.org/?format=json');
		|				JSONresponce = JSON.parse(responseText);
		|				$('body').text(JSONresponce.ip);
		|			} catch(ex) {
		|				try {
		|					responseText = httpGet('https://ipinfo.io/json');
		|					JSONresponce = JSON.parse(responseText);
		|					$('body').text(JSONresponce.ip);
		|				} catch(ex) {
		|					try {
		|						responseText = httpGet('https://www.cloudflare.com/cdn-cgi/trace?format=json');
		|						JSONresponce = JSON.parse(responseText);
		|						$('body').text(JSONresponce.ip);
		|					} catch(ex) {
		|						$('body').text('Блокирован');
		|					}
		|				}
		|			}
		|		};
		|		
		|		$(document).ready(function() {
		|			getIp();
		|		});
		|	</script>
		|</html>";
	Исключение
	КонецПопытки;
	
	// синхронное получение получает пустой ip т.к. js исполняется в отдельном потоке
	// асинхронное получение/ожидание
	ПодключитьОбработчикОжидания("ПопытатьсяПолучитьСодержаниеHTML", 1, Ложь);
КонецПроцедуры


&НаКлиенте
Процедура ПопытатьсяПолучитьСодержаниеHTML()
	Страница = Элементы.HTMLДокумент.Документ;
	Попытка
		ПопытокПолученияIPСделано = ПопытокПолученияIPСделано + 1;
		Если ЗначениеЗаполнено(Страница.body.innerHTML) Тогда
			ip = Страница.body.innerHTML;
			
			ОтключитьОбработчикОжидания("ПопытатьсяПолучитьСодержаниеHTML");
			СохранитьКлиентскийIPВПараметрыСеанса(ip);
			ЭтаФорма.Закрыть();
		КонецЕсли;
	Исключение
	КонецПопытки;
	
	// если попытки получения неудачны - закончить
	Если ПопытокПолученияIPСделано > 3 Тогда
		ОтключитьОбработчикОжидания("ПопытатьсяПолучитьСодержаниеHTML");
		ЭтаФорма.Закрыть();
	КонецЕсли;
КонецПроцедуры

&НаСервере
Процедура СохранитьКлиентскийIPВПараметрыСеанса(ip)
	ПараметрыСеанса.IpКлиента = ip;
КонецПроцедуры

 

ПриОткрытии() устанавливается тело HTML-документа с js, в js происходит попытка получения ip-адреса из одного из трех сервисов последовательно.
Если в браузере используется блокировщик — адреса ресурсов могут быть недоступны, в связи с чем получение ip-адреса ни из одного из ресурсов может не произойти, необходимо будет искать сервис, не находящийся в базе блокировщиков.
При успехе исполнения ip-адрес записывается в тело документа.

Каждую секунду в течение 3 секунд происходит асинхронная попытка получения текста HTML-документа (процедура ПопытатьсяПолучитьСодержаниеHTML()), в случае успеха происходит запись полученного значения в параметр сеанса.
После успеха или неуспеха форма закрывается.

  • Третье — время ее запуска. В нашем случае это модуль приложения, ПриНачалеРаботыСистемы().
    При начале работы системы запускаем обработку, активируем начальную страницу в попытке скрыть процесс работы обработки
    Процедура ПриНачалеРаботыСистемы()
    	
    	// СтандартныеПодсистемы
    	СтандартныеПодсистемыКлиент.ПриНачалеРаботыСистемы();
    	// Конец СтандартныеПодсистемы
    	
    	// определение ip-адреса клиента
    	ОткрытьФорму("Обработка.УстановкаIpКлиентаВПараметрыСеанса.Форма.Форма");
    	// активизировать главное окно
    	ОкнаПриложения = ПолучитьОкна();
    	Для Каждого Окно Из ОкнаПриложения Цикл
    		Если Окно.НачальнаяСтраница = Истина Тогда
    			Окно.Активизировать();
    		КонецЕсли;
    	КонецЦикла;		
    КонецПроцедуры

Вот и всё. Теперь мы почти всегда знаем, с какого IP к нам подключался клиент.

Надеюсь, в статье всё понятно. Ждём комментариев.

has been added to your cart:
Оформление заказа