[Python] Use custom authentication headers to access vector tiles in QGIS plugin

Discussão em 'Python' iniciado por Stack, Abril 7, 2025.

  1. Stack

    Stack Membro Participativo

    I didn't find the answer to my questions in the QGIS Python API docs, which I find very light in examples, but I'm quite new to QGIS and QGIS plugin creation, so I might be missing some things.

    What I'm trying to achieve


    I'm trying to build a python QGIS plugin to access my company's REST API. The API provides access to layer data:

    • Some routes (say /geojson/<layer_id>) directly return a GeoJSON that i can add to QGIS
    • Other routes (/vectortiles/<table>) give access to a vector tiles service mounted on a PostGreSQL table

    The API has an authentication system, so users must be authenticated for their requests to work. We have an API key system that allows authenticating using request headers, and I plan to use it in my plugin. Note that I could also use an authentication cookie.

    Concretely, the authentication headers look like this (we use mohawk):

    from mohawk import Sender

    class MyRequestClass:
    def get_headers(self, complete_url, method, content, content_type):
    """
    Evaluate complete dict of headers for a request.

    For requests using an API key, we use mohawk.Sender to
    create an authentication header.

    :param complete_url: request complete url
    :param method: request method
    :param content: request content
    :param content_type: request content type

    :return: dict of headers
    """
    # sign the request using mohawk.Sender
    sender = Sender(
    {
    "id": self.access_key_id,
    "key": self.secret_access_key,
    "algorithm": "sha256",
    },
    complete_url,
    method,
    content=content,
    content_type=content_type,
    )

    headers = dict() if headers is None else headers

    return {
    "Authorization": sender.request_header,
    "Content-Type": content_type,
    }

    What I managed to do on my own


    I started with the simpler case of the GeoJSON layers. Using the requests library and my get_headers function, I was able to request my API and read the GeoJSON result, then add it to GQIS. So it basically looks like this:

    Maybe this isn't the recommended way to do this, I've read some things about QgsNetworkAccessManager that seems to be recommended to make requests. Again I found very few documentation and examples on how to use it, so any tip is welcome.

    Now for the vector tiles layers. I first wanted to test if the import could work, so I accessed my locally hosted vector tiles service, bypassing my API. It works well.

    It looks like this:

    url = "type=xyz&http://localhost:3000/my_table/{z}/{x}/{y}"
    QgsVectorTileLayer(url, "my vector tiles layer")
    QgsProject.instance().addMapLayer(layer)

    Where I'm stuck


    Now I want to add vector tiles layers from my API, so I can access my deployed API.

    It seems to me that I cannot use the same code since I have to directly provide the url to the vector tiles layer: I cannot make the request myself.

    I've read a lot of documentation and I've crossed things that could possibly be solutions, but it stays really unclear to me, and the implementation seems furthermore impossible.

    Here are the various leads I have in mind:

    1. Maybe there is a way to configure the QgsNetworkAccessManager so when certain requests are made we provide my headers
    2. Maybe I could provide my headers as part as the string I give to QgsVectorTileLayer. I saw the QgsDataSourceUri (which use is recommended in the QgsVectorTileLayer doc) could be set with html headers, but I could not understand how it works
    3. I've been looking at the QGIS Authentication system, I thought maybe I had to implement a new authentication method ? By implementing the QgsAuthMethod ? Seems a lot but if its needed I can do this

    That's it, this post i already long enough. Hope someone can help me with this problem that seems pretty basic to me, so I hope I didn't miss something obvious.

    Thanks for reading me, have a good day.

    Continue reading...

Compartilhe esta Página