{"id":2127,"date":"2024-05-24T09:16:40","date_gmt":"2024-05-24T07:16:40","guid":{"rendered":"https:\/\/alessandromasciadri.com\/?p=2127"},"modified":"2024-05-24T09:20:07","modified_gmt":"2024-05-24T07:20:07","slug":"come-proteggere-una-rotta-flask-con-una-autenticazione-token-based","status":"publish","type":"post","link":"https:\/\/alessandromasciadri.com\/come-proteggere-una-rotta-flask-con-una-autenticazione-token-based\/","title":{"rendered":"Come proteggere una rotta Flask con una autenticazione Token-Based"},"content":{"rendered":"\t\t<div data-akihiro-type=\"ama-post\" data-akihiro-id=\"2127\" class=\"akihiro akihiro-2127\" data-akihiro-post-type=\"post\">\n\t\t\t\t<div class=\"akihiro-element akihiro-element-9933123 e-flex e-con-boxed e-con e-parent\" data-id=\"9933123\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"akihiro-element akihiro-element-4185e61 akihiro-widget akihiro-widget-text-editor\" data-id=\"4185e61\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"akihiro-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Questo articolo ha il solo scopo didattico di illustrare il meccanismo di autenticazione basato su token e il codice qui contenuto non \u00e8 adeguato per un ambiente di produzione senza opportune modifiche e migliorie. Inoltre, se si vuole implementare un meccanismo di autenticazione con token, si consiglia l&#8217;introduzione nel proprio progetto Flask di <a href=\"https:\/\/pypi.org\/project\/PyJWT\/\">PyJWT<\/a>, una libreria che implementa le specifiche <a href=\"https:\/\/datatracker.ietf.org\/doc\/html\/rfc7519\">RFC 7519<\/a>.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"akihiro-element akihiro-element-76cab4c e-flex e-con-boxed e-con e-parent\" data-id=\"76cab4c\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"akihiro-element akihiro-element-f04e6ae akihiro-widget akihiro-widget-heading\" data-id=\"f04e6ae\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"akihiro-widget-container\">\n\t\t\t\t\t<h3 class=\"akihiro-heading-title akihiro-size-default\">Autenticazione Flask basata su token<\/h3>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"akihiro-element akihiro-element-6e8e2c0 e-flex e-con-boxed e-con e-parent\" data-id=\"6e8e2c0\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"akihiro-element akihiro-element-d545f54 akihiro-widget akihiro-widget-text-editor\" data-id=\"d545f54\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"akihiro-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Anzitutto vediamo il codice nella sua interezza per poi procedere nei punti successivi a commentarlo pezzo per pezzo<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"akihiro-element akihiro-element-9828ba5 akihiro-widget akihiro-widget-code-highlight\" data-id=\"9828ba5\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"akihiro-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-tomorrow copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-python line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-python\">\n\t\t\t\t\t<xmp>from flask import Flask, request, jsonify\nimport uuid\n\napp = Flask(__name__)\n\n# Dummy authentication credentials\nUSERNAME = 'admin'      # Customize it\nPASSWORD = 'password'   # Customize it\n\n# Dummy token dictionary to store authentication tokens\ntokens = {}\n\n\n# Route to get authentication token\n@app.route('\/api\/v1\/get-token', methods=['POST'])\ndef get_token():\n    auth = request.authorization\n    if auth and auth.username == USERNAME and auth.password == PASSWORD:\n        token = uuid.uuid4().hex\n        tokens[token] = {'username': auth.username}\n        return jsonify({'token': token}), 200\n    else:\n        return jsonify({'error': 'Unauthorized access'}), 401\n\n\n# Token authentication decorator\ndef token_required(func):\n    def wrapper(*args, **kwargs):\n        token = request.headers.get('Authorization')\n\n        if token and token.split()[1] in tokens:\n            return func(*args, **kwargs)\n        else:\n            return jsonify({'error': 'Token is missing or invalid'}), 401\n    return wrapper\n\n\n# Route to be protected with token authentication\n@app.route('\/api\/your-endpoint', methods=['POST'])\n@token_required\ndef your_endpoint():\n    pass\n\n\nif __name__ == '__main__':\n    app.run(debug=True)<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"akihiro-element akihiro-element-791d559 akihiro-widget akihiro-widget-heading\" data-id=\"791d559\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"akihiro-widget-container\">\n\t\t\t\t\t<h3 class=\"akihiro-heading-title akihiro-size-default\">Considerazioni iniziali sulla sicurezza<\/h3>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"akihiro-element akihiro-element-9beea1b akihiro-widget akihiro-widget-text-editor\" data-id=\"9beea1b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"akihiro-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Anzitutto \u00e8 necessario ribadire che questo codice ha solo scopo didattico e non \u00e8 adatto per la produzione. Il primo aspetto \u00e8 relativo al fattore sicurezza. Ovviamente le costanti USERNAME e PASSWORD dovranno essere sostituite ed un sicuro sistema di autenticazione utente mediante username e password deve essere implementato.<\/p><p>Altra cosa da sostituire \u00e8 il salvataggio del token e qui esistono molteplici aspetti che potrebbero essere discussi, ma che prescindono dallo scopo di questo articolo. Teniamo semplicemente a mente che salvare i token in un dizionario \u00e8 una mossa non saggia e da evitare.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"akihiro-element akihiro-element-ebc20c2 akihiro-widget akihiro-widget-code-highlight\" data-id=\"ebc20c2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"akihiro-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-tomorrow copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-python line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-python\">\n\t\t\t\t\t<xmp># Dummy authentication credentials\nUSERNAME = 'admin'      # Customize it\nPASSWORD = 'password'   # Customize it\n\n# Dummy token dictionary to store authentication tokens\ntokens = {}<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"akihiro-element akihiro-element-9de76df akihiro-widget akihiro-widget-heading\" data-id=\"9de76df\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"akihiro-widget-container\">\n\t\t\t\t\t<h3 class=\"akihiro-heading-title akihiro-size-default\">Rilascio del token<\/h3>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"akihiro-element akihiro-element-bc1b2f2 akihiro-widget akihiro-widget-text-editor\" data-id=\"bc1b2f2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"akihiro-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>L&#8217;endpoint get-token \u00e8 colui che dovr\u00e0 essere invocato per ottenere il token di autenticazione. In questo esempio vengono verificate le credenziali USERNAME e PASSWORD, ma come abbiamo detto nelle considerazioni precedenti, la logica di controllo dell&#8217;autenticazione va implementata ex novo.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"akihiro-element akihiro-element-a29898f akihiro-widget akihiro-widget-code-highlight\" data-id=\"a29898f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"akihiro-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-tomorrow copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-python line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-python\">\n\t\t\t\t\t<xmp># Route to get authentication token\n@app.route('\/api\/v1\/get-token', methods=['POST'])\ndef get_token():\n    auth = request.authorization\n    if auth and auth.username == USERNAME and auth.password == PASSWORD:\n        token = uuid.uuid4().hex\n        tokens[token] = {'username': auth.username}\n        return jsonify({'token': token}), 200\n    else:\n        return jsonify({'error': 'Unauthorized access'}), 401<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"akihiro-element akihiro-element-3a62be6 akihiro-widget akihiro-widget-heading\" data-id=\"3a62be6\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"akihiro-widget-container\">\n\t\t\t\t\t<h3 class=\"akihiro-heading-title akihiro-size-default\">Decoratore ed endpoint da proteggere<\/h3>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"akihiro-element akihiro-element-77f3230 akihiro-widget akihiro-widget-text-editor\" data-id=\"77f3230\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"akihiro-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Questo decoratore \u00e8 colui che andremo ad applicare al nostro endpoint per proteggerlo mediante autenticazione basata su token<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"akihiro-element akihiro-element-e6a327a akihiro-widget akihiro-widget-code-highlight\" data-id=\"e6a327a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"akihiro-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-tomorrow copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-python line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-python\">\n\t\t\t\t\t<xmp># Token authentication decorator\ndef token_required(func):\n    def wrapper(*args, **kwargs):\n        token = request.headers.get('Authorization')\n\n        if token and token.split()[1] in tokens:\n            return func(*args, **kwargs)\n        else:\n            return jsonify({'error': 'Token is missing or invalid'}), 401\n    return wrapper<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"akihiro-element akihiro-element-00fca35 akihiro-widget akihiro-widget-text-editor\" data-id=\"00fca35\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"akihiro-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Ed ecco qui il nostro endpoint protetto<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"akihiro-element akihiro-element-adc0f56 akihiro-widget akihiro-widget-code-highlight\" data-id=\"adc0f56\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"akihiro-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-tomorrow copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-python line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-python\">\n\t\t\t\t\t<xmp># Route to be protected with token authentication\n@app.route('\/api\/v1\/your-endpoint', methods=['POST'])\n@token_required\ndef your_endpoint():\n    pass<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Questo articolo ha il solo scopo didattico di illustrare il meccanismo di autenticazione basato su token e il codice qui contenuto non \u00e8 adeguato per un ambiente di produzione senza opportune modifiche e migliorie. Inoltre, se si vuole implementare un meccanismo di autenticazione con token, si consiglia l&#8217;introduzione nel proprio progetto Flask di PyJWT, una [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[28,12],"class_list":["post-2127","post","type-post","status-publish","format-standard","hentry","category-programmazione","tag-flask","tag-python"],"_links":{"self":[{"href":"https:\/\/alessandromasciadri.com\/ama-json\/wp\/v2\/posts\/2127","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/alessandromasciadri.com\/ama-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/alessandromasciadri.com\/ama-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/alessandromasciadri.com\/ama-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/alessandromasciadri.com\/ama-json\/wp\/v2\/comments?post=2127"}],"version-history":[{"count":16,"href":"https:\/\/alessandromasciadri.com\/ama-json\/wp\/v2\/posts\/2127\/revisions"}],"predecessor-version":[{"id":2143,"href":"https:\/\/alessandromasciadri.com\/ama-json\/wp\/v2\/posts\/2127\/revisions\/2143"}],"wp:attachment":[{"href":"https:\/\/alessandromasciadri.com\/ama-json\/wp\/v2\/media?parent=2127"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/alessandromasciadri.com\/ama-json\/wp\/v2\/categories?post=2127"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/alessandromasciadri.com\/ama-json\/wp\/v2\/tags?post=2127"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}