Библиотека Leaflet сама по себе не реализует механизмы аутентификации пользователей или авторизации доступа к данным. Однако в реальных веб-приложениях карта часто взаимодействует с защищёнными сервисами:
Во всех подобных случаях запросы к серверу должны содержать данные для подтверждения личности пользователя или приложения.
Наиболее распространённые способы аутентификации:
Leaflet выступает клиентом, который отправляет запросы к защищённым ресурсам и отображает полученные данные на карте.
Многие картографические сервисы используют API-ключ как самый простой механизм контроля доступа.
Пример URL с ключом:
https://api.example.com/tiles/{z}/{x}/{y}.png?apikey=YOUR_KEY
Подключение слоя:
const map = L.map('map').setView([55.751244, 37.618423], 10);
L.tileLayer(
'https://api.example.com/tiles/{z}/{x}/{y}.png?apikey=YOUR_KEY',
{
maxZoom: 19
}
).addTo(map);
При каждом запросе тайла ключ автоматически передаётся серверу.
Преимущества:
Недостатки:
Никогда не следует считать клиентский код безопасным местом хранения секретов.
Плохой вариант:
const apiKey = "super-secret-key";
После публикации приложения значение становится доступным любому пользователю через инструменты разработчика.
Более безопасный подход:
fetch('/api/config')
.then(response => response.json())
.then(config => {
L.tileLayer(
`https://api.example.com/{z}/{x}/{y}.png?apikey=${config.key}`
).addTo(map);
});
Даже в этом случае ключ остаётся доступным клиенту, поэтому рекомендуется:
Современные API часто используют JWT-токены.
Типичный HTTP-заголовок:
Authorization: Bearer eyJhbGciOi...
Стандартный слой L.TileLayer не позволяет напрямую
задавать произвольные заголовки для загрузки тайлов через элемент
<img>.
Поэтому для защищённых ресурсов обычно применяется один из следующих подходов:
Часто геоданные загружаются отдельно, а затем отображаются на карте.
Пример:
fetch('/api/points', {
headers: {
Authorization: `Bearer ${token}`
}
})
.then(response => response.json())
.then(data => {
L.geoJSON(data).addTo(map);
});
Сервер получает токен и может определить права пользователя.
Такой подход особенно распространён при работе с:
Рассмотрим полный пример.
async function loadObjects() {
const response = await fetch('/api/objects', {
headers: {
Authorization: `Bearer ${token}`
}
});
const geojson = await response.json();
L.geoJSON(geojson, {
onEachFeature(feature, layer) {
layer.bindPopup(feature.properties.name);
}
}).addTo(map);
}
loadObjects();
Процесс выглядит следующим образом:
Во многих корпоративных приложениях применяется сессионная авторизация.
После входа пользователь получает cookie:
Set-Cookie: sessionid=123456
При выполнении запросов браузер автоматически отправляет cookie серверу.
Пример:
fetch('/api/objects', {
credentials: 'include'
})
.then(response => response.json())
.then(data => {
L.geoJSON(data).addTo(map);
});
Параметр:
credentials: 'include'
указывает браузеру отправлять cookie даже при междоменных запросах.
Leaflet активно используется для подключения WMS-серверов.
Пример слоя:
L.tileLayer.wms(
'https://maps.example.com/wms',
{
layers: 'roads',
format: 'image/png',
transparent: true
}
).addTo(map);
Если сервер требует авторизацию через URL:
L.tileLayer.wms(
'https://maps.example.com/wms?token=abc123',
{
layers: 'roads'
}
).addTo(map);
Однако более безопасным считается использование серверного шлюза.
Схема работы:
Leaflet
↓
Backend Proxy
↓
Protected WMS
Пользователь взаимодействует только с собственным сервером приложения, который уже выполняет аутентифицированные запросы к картографическому сервису.
Прокси-сервер часто используется для сокрытия токенов и ключей.
Архитектура:
Browser
↓
Application Server
↓
Map Service
Клиентский код:
L.tileLayer('/tiles/{z}/{x}/{y}')
.addTo(map);
Сервер:
app.get('/tiles/:z/:x/:y', async (req, res) => {
const url = createRemoteUrl(req.params);
const response = await fetch(url, {
headers: {
Authorization: 'Bearer SECRET_TOKEN'
}
});
response.body.pipe(res);
});
Преимущества:
Иногда возникает необходимость отправлять HTTP-заголовки для каждого тайла.
Для этого создаётся наследник L.TileLayer.
Пример концепции:
const SecureTileLayer = L.TileLayer.extend({
createTile(coords, done) {
const tile = document.createElement('img');
const url = this.getTileUrl(coords);
fetch(url, {
headers: {
Authorization: `Bearer ${token}`
}
})
.then(response => response.blob())
.then(blob => {
tile.src = URL.createObjectURL(blob);
done(null, tile);
});
return tile;
}
});
Использование:
const layer = new SecureTileLayer(
'https://api.example.com/{z}/{x}/{y}'
);
layer.addTo(map);
Такой механизм позволяет работать с сервисами, которые принимают данные аутентификации исключительно через заголовки.
JWT имеет ограниченный срок действия.
Типичная схема:
Access Token
↓
Истекает
↓
Refresh Token
↓
Получение нового Access Token
Перед загрузкой геоданных:
async function authorizedFetch(url) {
let response = await fetch(url, {
headers: {
Authorization: `Bearer ${accessToken}`
}
});
if (response.status === 401) {
await refreshAccessToken();
response = await fetch(url, {
headers: {
Authorization: `Bearer ${accessToken}`
}
});
}
return response;
}
После обновления токена карта продолжает работать без повторной авторизации пользователя.
Получение объектов карты часто зависит от прав доступа.
Пример:
async function loadMarkers() {
const response = await fetch('/api/markers', {
headers: {
Authorization: `Bearer ${token}`
}
});
const markers = await response.json();
markers.forEach(marker => {
L.marker([
marker.lat,
marker.lng
])
.bindPopup(marker.title)
.addTo(map);
});
}
Сервер может возвращать:
Аутентификация подтверждает личность пользователя.
Авторизация определяет его права.
Пример ролей:
Admin
Operator
Manager
Guest
После проверки токена сервер может фильтровать данные:
if (user.role === 'Guest') {
return publicObjects;
}
if (user.role === 'Manager') {
return regionalObjects;
}
return allObjects;
Leaflet получает уже отфильтрованный набор пространственных данных.
Многие карты отображают данные в реальном времени.
Например:
Подключение:
const socket = new WebSocket(
`wss://api.example.com/live?token=${token}`
);
После аутентификации сервер начинает передавать координаты:
socket.onmess age = event => {
const data = JSON.parse(event.data);
marker.setLatLng([
data.lat,
data.lng
]);
};
Некоторые организации публикуют карты исключительно для внутренних пользователей.
Популярные способы защиты:
При использовании Leaflet схема не меняется: карта отображает только те тайлы, которые сервер разрешил получить после успешной проверки учётных данных.
OAuth применяется при интеграции с внешними сервисами.
Типичный процесс:
Пользователь
↓
OAuth Provider
↓
Access Token
↓
Leaflet Application
↓
Protected API
После получения токена карта может выполнять запросы:
fetch('/api/geo', {
headers: {
Authorization: `Bearer ${oauthToken}`
}
})
.then(response => response.json())
.then(data => {
L.geoJSON(data).addTo(map);
});
Такой подход широко используется при интеграции с облачными геоинформационными платформами и корпоративными системами единого входа.
Небезопасный вариант:
const token = "hardcoded-token";
Любой пользователь сможет получить значение.
Небезопасно:
http://example.com
Без шифрования токены могут быть перехвачены.
Следует использовать исключительно:
https://example.com
Плохо:
Access Token: 365 дней
Предпочтительнее:
Access Token: 5–30 минут
Refresh Token: длительный срок
Недопустимо:
const adminKey = "...";
Подобные ключи должны использоваться только на серверной стороне.
Перед выполнением запросов необходимо контролировать актуальность токена и своевременно выполнять процедуру обновления.
Для производственных систем наиболее распространён следующий подход:
Leaflet
↓
Backend API
↓
Authentication Service
↓
Protected GIS Services
Характерные особенности такой архитектуры:
Такой подход обеспечивает безопасную работу Leaflet-приложений с корпоративными геоданными, приватными тайловыми серверами и внешними картографическими API.