JSON-webtokens zijn eenvoudig te gebruiken en te debuggen, maar ze bieden ook een indrukwekkende beveiligingsboost.

Verbroken authenticatie blijft een hardnekkige kwetsbaarheid in moderne webapplicaties. Het staat nog steeds hoog in OWASP's top 10 API-beveiligingsrisico's.

De gevolgen van deze kwetsbaarheid kunnen ernstig zijn. Ze kunnen ongeautoriseerde toegang verlenen tot gevoelige gegevens en de systeemintegriteit in gevaar brengen. Om effectief te zorgen voor veilige toegang tot applicaties en hun bronnen, is het essentieel dat u robuuste authenticatiemechanismen gebruikt.

Ontdek hoe u gebruikersauthenticatie in Flask kunt implementeren met behulp van JSON Web Tokens (JWT), een populaire en effectieve op tokens gebaseerde methode.

Op tokens gebaseerde authenticatie met behulp van JSON-webtokens

Op tokens gebaseerde authenticatie gebruikt een gecodeerde tekenreeks om de toegang tot een systeem of bron te valideren en te autoriseren. U kunt dit type authenticatie op verschillende manieren implementeren, waaronder sessietokens, API-sleutels en JSON-webtokens.

Met name JWT's bieden een veilige en compacte benadering voor het verzenden van de vereiste gebruikersreferenties tussen client-side applicaties en servers.

Een JWT bestaat uit drie hoofdcomponenten: de header, de payload en de handtekening. De header bevat metadata over het token, inclusief het hash-algoritme dat wordt gebruikt om het token te coderen.

De payload bevat de eigenlijke gebruikersreferenties, zoals gebruikers-ID en machtigingen. Ten slotte verzekert de handtekening de geldigheid van het token door de inhoud ervan te verifiëren met behulp van een geheime sleutel.

Met JWT's kunt u gebruikers authenticeren en sessiegegevens opslaan, allemaal in het token zelf.

Zet een Flask-project en een MongoDB-database op

Maak om te beginnen een nieuwe projectdirectory aan met behulp van een terminal:

mkdir fles-project
cd flask-project

Installeer vervolgens virtualenv, om een ​​lokale virtuele ontwikkelomgeving voor uw Flask-project te creëren.

virtualenv venv

Activeer ten slotte de virtuele omgeving.

# Unix of macOS: 
source venv/bin/activeren

# Ramen:
.\venv\Scripts\activeren

U kunt de code van dit project hierin vinden GitHub-opslagplaats.

Installeer de vereiste pakketten

Maak in de hoofdmap van uw projectmap een nieuw vereisten.txt bestand en voeg deze afhankelijkheden voor het project toe:

kolf
pjwt
python-dotenv
pymongo
bcrypt

Voer ten slotte de onderstaande opdracht uit om de pakketten te installeren. Zorg dat je hebt Pip (pakketbeheerder) geïnstalleerd; als niet, installeer het op uw Windows-, Mac- of Linux-systeem.

pip install -r vereisten.txt

Maak een MongoDB-database

Ga je gang en maak een MongoDB-database. Jij kan een lokale MongoDB-database opzetten, alternatief, maak een cluster op MongoDB Atlas, een cloudgebaseerde MongoDB-service.

Nadat u de database hebt gemaakt, kopieert u de verbindings-URI, maakt u een .env bestand in de hoofdmap van uw project en voeg het als volgt toe:

MONGO_URI=""

Configureer ten slotte de databaseverbinding vanuit uw Flask-toepassing. Maak een nieuwe aan utils/db.py bestand in de hoofdmap van uw project, met deze code:

van pymongo importeren MongoClient

defconnect_to_mongodb(mongo_uri):
klant = MongoClient (mongo_uri)
db = client.get_database("gebruikers")
opbrengst db

Deze functie brengt een verbinding tot stand met de MongoDB-database met behulp van de opgegeven verbindings-URI. Vervolgens maakt hij een nieuwe aan gebruikers verzameling als deze niet bestaat, en retourneert de overeenkomstige database-instantie.

Maak de Flask-webserver

Met de database geconfigureerd, ga je gang en maak je een app.py bestand in de hoofdmap van de projectmap en voeg de volgende code toe om een ​​exemplaar van de Flask-toepassing te maken.

van kolf importeren Fles
van routes.user_auth importeren register_routes
van utils.db importeren connect_to_mongodb
importeren os
van dotenv importeren load_dotenv

app = Fles (__naam__)
load_dotenv()

mongo_uri = os.getenv('MONGO_URI')
db = connect_to_mongodb (mongo_uri)

register_routes (app, db)

als __naam__ == '__voornaamst__':
app.run (debug=WAAR)

Maak de verificatie-API-eindpunten

Om gebruikersauthenticatie in uw Flask-toepassing te implementeren, is het cruciaal om de benodigde API-eindpunten te definiëren die authenticatiegerelateerde bewerkingen afhandelen.

Definieer echter eerst het model voor de gegevens van de gebruikers. Maak hiervoor een nieuwe aan model/user_model.py bestand in de hoofdmap en voeg de volgende code toe.

van pymongo.collectie importeren Verzameling
van bson.objectid importeren Object-ID

klasGebruiker:
def__in het__(zelf, verzameling: Verzameling, gebruikersnaam: str, wachtwoord: str):
self.collection = collectie
self.username = gebruikersnaam
zelf.wachtwoord = wachtwoord
defredden(zelf):
gebruikersgegevens = {
'gebruikersnaam': zelf.gebruikersnaam,
'wachtwoord': zelf.wachtwoord
}
resultaat = self.collection.insert_one (user_data)
opbrengst str (resultaat.ingevoegd_id)

@statischemethode
defvind_op_id(verzameling: Verzameling, user_id: str):
opbrengst collectie.find_one({'_ID kaart': ObjectId (user_id)})

@statischemethode
defvind_op_gebruikersnaam(collectie: collectie, gebruikersnaam: str):
opbrengst collectie.find_one({'gebruikersnaam': gebruikersnaam})

De bovenstaande code specificeert a Gebruiker klasse die dient als een gegevensmodel en verschillende methoden definieert voor interactie met een MongoDB-verzameling om gebruikersgerelateerde bewerkingen uit te voeren.

  1. De redden methode slaat een nieuw gebruikersdocument met de verstrekte gebruikersnaam en wachtwoord op in de MongoDB-verzameling en retourneert de ID van het ingevoegde document.
  2. De vind_op_id En vind_op_gebruikersnaam methodes halen gebruikersdocumenten op uit de collectie op basis van respectievelijk de verstrekte gebruikers-ID of gebruikersnaam.

Definieer de authenticatieroutes

  1. Laten we beginnen met het definiëren van de registratieroute. Deze route voegt nieuwe gebruikersgegevens toe aan de MongoDB-gebruikersverzameling. Maak in de hoofdmap een nieuw routes/user_auth.py bestand en de volgende code.
    importeren jwt
    van funtools importeren omslagen
    van kolf importeren jsonify, verzoek, make_response
    van modellen.gebruiker_model importeren Gebruiker
    importeren bcrypt
    importeren os

    defregister_routes(app, database):
    verzameling = db.gebruikers
    app.config['GEHEIME SLEUTEL'] = os.urandom(24)

    @app.route('/api/register', methods=['POST'])
    defregister():

    gebruikersnaam = request.json.get('gebruikersnaam')
    wachtwoord = verzoek.json.get('wachtwoord')

    bestaande_gebruiker = User.find_by_username (verzameling, gebruikersnaam)
    als bestaande gebruiker:
    opbrengst jsonify({'bericht': 'Gebruikersnaam bestaat al!'})

    hash_password = bcrypt.hashpw (password.encode('utf-8'), bcrypt.gensalt())
    new_user = Gebruiker (verzameling, gebruikersnaam, hashed_password.decode('utf-8'))
    user_id = nieuwe_gebruiker.save()

    opbrengst jsonify({'bericht': 'Gebruiker succesvol geregistreerd!', 'gebruikersnaam': gebruikersnaam})

  2. Implementeer de inlogfunctionaliteit om het authenticatieproces af te handelen en gebruikersreferenties te verifiëren. Voeg onder de registratieroute de volgende code toe.
     @app.route('/api/login', methods=['POST'])
    defLog in():
    gebruikersnaam = request.json.get('gebruikersnaam')
    wachtwoord = verzoek.json.get('wachtwoord')
    user = User.find_by_username (verzameling, gebruikersnaam)
    als gebruiker:
    als bcrypt.checkpw (wachtwoord.coderen('utf-8'), gebruiker['wachtwoord'].coderen('utf-8')):
    token = jwt.encode({'gebruikersnaam': str (gebruiker['_ID kaart'])}, app.config['GEHEIME SLEUTEL'], algoritme='HS256')

    antwoord = maak_antwoord (jsonify({'bericht': 'Succesvol ingelogd!'}))
    reactie.set_cookie('teken', teken)
    opbrengst antwoord

    opbrengst jsonify({'bericht': 'Ongeldige gebruikersnaam of wachtwoord'})

    Het login-eindpunt doet twee dingen: het verifieert de opgegeven gebruikersreferenties en na succesvolle authenticatie genereert het een unieke JWT voor die gebruiker. Het stelt dit token in als een cookie in het antwoord, samen met een JSON-payload die een succesvolle login aangeeft. Als de inloggegevens ongeldig zijn, retourneert het een JSON-antwoord om dit aan te geven.
  3. Definieer een decorateurfunctie die de JSON Web Tokens (JWT's) verifieert die samen met volgende API-verzoeken worden doorgegeven. Voeg de onderstaande code toe in de register_routes functie code blok.
    deftoken_vereist(F):
    @wraps (v)
    defingericht(*args, **kwargs):
    token = aanvraag.cookies.get('teken')

    alsniet token:
    opbrengst jsonify({'bericht': 'Token ontbreekt!'}), 401

    poging:
    data = jwt.decode (token, app.config['GEHEIME SLEUTEL'], algoritmen=['HS256'])
    current_user = User.find_by_id (verzameling, gegevens['gebruikersnaam'])
    behalve jwt. VerlopenHandtekeningError:
    opbrengst jsonify({'bericht': 'Token is verlopen!'}), 401
    behalve jwt. InvalidTokenError:
    opbrengst jsonify({'bericht': 'Ongeldige Token!'}), 401

    opbrengst f (huidige_gebruiker, *args, **kwargs)

    opbrengst ingericht

    Deze decorateurfunctie zorgt voor de aanwezigheid van een geldig JWT-token in volgende API-verzoeken. Het controleert of het token ontbreekt, is verlopen of geldig, en retourneert een geschikt JSON-antwoord als dat zo is.
  4. Maak ten slotte een beschermde route.
     @app.route('/api/users', methods=['GET'])
    @token_required
    defkrijg_gebruikers(huidige gebruiker):
    gebruikers = lijst (collection.find({}, {'_ID kaart': 0}))
    opbrengst jsonify (gebruikers)

Dit eindpunt verwerkt de logica voor het ophalen van gebruikersgegevens uit de database, maar vereist dat de client die verzoeken verzendt een geldig token opneemt om toegang te krijgen tot de gegevens.

Voer ten slotte de onderstaande opdracht uit om de ontwikkelingsserver te laten draaien.

kolf lopen

Om de registratie, login en het eindpunt van de beschermde gebruiker te testen, kunt u Postman of een andere API-client gebruiken. Verzoekjes sturen naar http://localhost: 5000/api/en observeer de antwoorden om de functionaliteit van deze API-eindpunten te verifiëren.

Is tokenverificatie een waterdichte beveiligingsmaatregel?

JSON-webtokens bieden een robuuste en effectieve manier om gebruikers voor uw web-app te verifiëren. Het is echter belangrijk om te begrijpen dat tokenauthenticatie niet onfeilbaar is; het is slechts een stukje van een grotere beveiligingspuzzel.

Combineer tokenverificatie met andere best practices op het gebied van beveiliging. Vergeet niet om continu te monitoren en consistente beveiligingspraktijken toe te passen; u verbetert de algehele beveiliging van uw Flask-applicaties aanzienlijk.