JSON Web Tokens är lätta att använda och felsöka, men de erbjuder också en imponerande säkerhetshöjning.
Trasig autentisering fortsätter att vara en ihållande sårbarhet i moderna webbapplikationer – den rankas fortfarande högt bland OWASP: s topp 10 API-säkerhetsrisker.
Effekterna av denna sårbarhet kan vara allvarliga. De kan ge obehörig åtkomst till känsliga data och äventyra systemets integritet. För att effektivt säkerställa säker åtkomst till applikationer och deras resurser är det viktigt att du använder robusta autentiseringsmekanismer.
Ta reda på hur du kan implementera användarautentisering i Flask med JSON Web Tokens (JWT), en populär och effektiv tokenbaserad metod.
Token-baserad autentisering med JSON Web Tokens
Tokenbaserad autentisering använder en krypterad teckensträng för att validera och auktorisera åtkomst till ett system eller en resurs. Du kan implementera den här typen av autentisering med olika metoder, inklusive sessionstokens, API-nycklar och JSON Web Tokens.
JWT, i synnerhet, erbjuder ett säkert och kompakt tillvägagångssätt för att överföra de nödvändiga användarnas referenser mellan applikationer och servrar på klientsidan.
En JWT består av tre huvudkomponenter: rubriken, nyttolasten och signaturen. Rubriken innehåller metadata om token, inklusive hashalgoritmen som används för att koda token.
Nyttolasten innehåller de faktiska användaruppgifterna, såsom användar-ID och behörigheter. Slutligen säkerställer signaturen tokens giltighet genom att verifiera dess innehåll med hjälp av en hemlig nyckel.
Med JWT: er kan du autentisera användare och lagra sessionsdata allt inom själva tokenet.
Konfigurera ett kolvprojekt och en MongoDB-databas
För att komma igång, skapa en ny projektkatalog med en terminal:
mkdir kolv-projekt
cd-flask-projekt
Installera sedan virtualenv, för att skapa en lokal virtuell utvecklingsmiljö för ditt Flask-projekt.
virtualenv venv
Slutligen, aktivera den virtuella miljön.
# Unix eller MacOS:
source venv/bin/activate
# Windows:
.\venv\Scripts\aktivera
Du kan hitta detta projekts kod i denna GitHub-förråd.
Installera de nödvändiga paketen
Skapa en ny i rotkatalogen i din projektmapp krav.txt fil och lägg till dessa beroenden för projektet:
flaska
pyjwt
python-dotenv
pymongo
bcrypt
Slutligen, kör kommandot nedan för att installera paketen. Se till att du har pip (pakethanterare) installerad; om inte, installera det på ditt Windows-, Mac- eller Linux-system.
pip installation -r requirements.txt
Skapa en MongoDB-databas
Fortsätt och skapa en MongoDB-databas. Du kan skapa en lokal MongoDB-databas, alternativt, skapa ett kluster på MongoDB Atlas, en molnbaserad MongoDB-tjänst.
När du har skapat databasen, kopiera anslutnings-URI, skapa en .env fil i rotkatalogen för ditt projekt och lägg till den enligt följande:
MONGO_URI=""
Slutligen konfigurerar du databasanslutningen från din Flask-applikation. Skapa en ny utils/db.py fil i rotkatalogen för ditt projekt, med denna kod:
från pymongo importera MongoClient
defconnect_to_mongodb(mongo_uri):
klient = MongoClient (mongo_uri)
db = klient.get_database("användare")
lämna tillbaka db
Den här funktionen upprättar en anslutning till MongoDB-databasen med hjälp av den tillhandahållna anslutnings-URI. Det skapar sedan en ny användare samling om den inte finns, och returnerar motsvarande databasinstans.
Skapa Flask Web Server
Med databasen konfigurerad, fortsätt och skapa en app.py fil i projektmappens rotkatalog och lägg till följande kod för att skapa en instans av Flask-applikationen.
från flaska importera Flaska
från routes.user_auth importera register_rutter
från utils.db importera connect_to_mongodb
importera os
från dotenv importera load_dotenvapp = Kolv (__namn__)
load_dotenv()mongo_uri = os.getenv('MONGO_URI')
db = connect_to_mongodb (mongo_uri)register_routes (app, db)
om __namn__ == '__main__':
app.run (debug=Sann)
Skapa Authentication API Endpoints
För att implementera användarautentisering i din Flask-applikation är det avgörande att definiera de nödvändiga API-slutpunkterna som hanterar autentiseringsrelaterade operationer.
Men först, definiera modellen för användarnas data. För att göra det, skapa en ny model/user_model.py fil i rotkatalogen och lägg till följande kod.
från pymongo.samling importera Samling
från bson.objectid importera ObjectIdklassAnvändare:
def__i det__(själv, samling: Samling, användarnamn: str, lösenord: str):
self.collection = samling
self.username = användarnamn
self.password = lösenord
defspara(själv):
user_data = {
'Användarnamn': self.username,
'Lösenord': själv.lösenord
}
resultat = self.collection.insert_one (user_data)
lämna tillbaka str (result.inserted_id)@statisk metod
defhitta_efter_id(samling: samling, user_id: str):
lämna tillbaka collection.find_one({'_id': ObjectId (user_id)})
@statisk metod
defhitta_efter_användarnamn(samling: Samling, användarnamn: str):
lämna tillbaka collection.find_one({'Användarnamn': Användarnamn})
Koden ovan anger en Användare klass som fungerar som en datamodell och definierar flera metoder för att interagera med en MongoDB-samling för att utföra användarrelaterade operationer.
- De spara metoden sparar ett nytt användardokument med det angivna användarnamnet och lösenordet till MongoDB-samlingen och returnerar ID: t för det infogade dokumentet.
- De hitta_efter_id och hitta_efter_användarnamn metoder hämtar användardokument från samlingen baserat på det angivna användar-ID eller användarnamn.
Definiera autentiseringsrutter
- Låt oss börja med att definiera registreringsvägen. Den här rutten kommer att lägga till ny användardata till MongoDB-användarsamlingen. Skapa en ny i rotkatalogen routes/user_auth.py fil och följande kod.
importera jwt
från funktionsverktyg importera wraps
från flaska importera jsonify, request, make_response
från models.user_model importera Användare
importera bcrypt
importera osdefregister_rutter(app, db):
samling = db.användare
app.config['HEMLIG NYCKEL'] = os.urandom(24)@app.route('/api/register', methods=['POST'])
defRegistrera():
användarnamn = request.json.get('Användarnamn')
lösenord = request.json.get('Lösenord')
existerande_användare = User.find_by_username (samling, användarnamn)
om existerande användare:
lämna tillbaka jsonify({'meddelande': 'Användarnamn existerar redan!'})
hashed_password = bcrypt.hashpw (password.encode('utf-8'), bcrypt.gensalt())
new_user = Användare (samling, användarnamn, hashed_password.decode('utf-8'))
user_id = new_user.save()lämna tillbaka jsonify({'meddelande': 'Användaren har registrerats framgångsrikt!', 'användar ID': användar ID})
- Implementera inloggningsfunktionen för att hantera autentiseringsprocessen och verifiera användaruppgifter. Lägg till följande kod under registreringsrutten.
Inloggningsslutpunkten gör två saker: den verifierar de angivna användaruppgifterna och, efter framgångsrik autentisering, genererar den en unik JWT för den användaren. Den ställer in denna token som en cookie i svaret, tillsammans med en JSON-nyttolast som indikerar en lyckad inloggning. Om autentiseringsuppgifterna är ogiltiga returneras ett JSON-svar för att indikera det.@app.route('/api/login', methods=['POST'])
deflogga in():
användarnamn = request.json.get('Användarnamn')
lösenord = request.json.get('Lösenord')
user = User.find_by_username (samling, användarnamn)
om användare:
om bcrypt.checkpw (password.encode('utf-8'), användare['Lösenord'].koda('utf-8')):
token = jwt.encode({'användar ID': str (användare['_id'])}, app.config['HEMLIG NYCKEL'], algoritm='HS256')
respons = make_response (jsonify({'meddelande': 'Inloggningen lyckades!'}))
response.set_cookie('tecken', token)
lämna tillbaka svarlämna tillbaka jsonify({'meddelande': 'Ogiltigt användarnamn eller lösenord'})
- Definiera en dekorationsfunktion som verifierar JSON Web Tokens (JWT) som skickas tillsammans med efterföljande API-förfrågningar. Lägg till koden nedan inom register_rutter funktionskodblock.
Denna dekorationsfunktion säkerställer närvaron av en giltig JWT-token i efterföljande API-förfrågningar. Den kontrollerar om token saknas, har gått ut eller är giltig och returnerar ett lämpligt JSON-svar om det är det.deftoken_required(f):
@wraps (f)
defdekorerad(*args, **kwargs):
token = request.cookies.get('tecken')ominte tecken:
lämna tillbaka jsonify({'meddelande': "Token saknas!"}), 401Prova:
data = jwt.decode (token, app.config['HEMLIG NYCKEL'], algoritmer=['HS256'])
current_user = User.find_by_id (insamling, data['användar ID'])
bortsett från jwt. ExpiredSignatureError:
lämna tillbaka jsonify({'meddelande': 'Token har gått ut!'}), 401
bortsett från jwt. InvalidTokenError:
lämna tillbaka jsonify({'meddelande': "Ogiltig token!"}), 401lämna tillbaka f (current_user, *args, **kwargs)
lämna tillbaka dekorerad
- Slutligen, skapa en skyddad rutt.
@app.route('/api/users', methods=['GET'])
@token_required
defget_users(nuvarande användaren):
användare = lista (collection.find({}, {'_id': 0}))
lämna tillbaka jsonify (användare)
Denna slutpunkt hanterar logiken för att hämta användardata från databasen, men den kräver att klienten som skickar förfrågningar inkluderar en giltig token för att komma åt data.
Slutligen, kör kommandot nedan för att snurra upp utvecklingsservern.
kolvkörning
För att testa registreringen, inloggningen och de skyddade användarnas slutpunkt kan du använda Postman eller någon annan API-klient. Skicka förfrågningar till http://localhost: 5000/api/och observera svaren för att verifiera funktionaliteten hos dessa API-slutpunkter.
Är tokenautentisering en idiotsäker säkerhetsåtgärd?
JSON Web Tokens ger ett robust och effektivt sätt att autentisera användare för din webbapp. Det är dock viktigt att förstå att token-autentisering inte är idiotsäker; det är bara en del av ett större säkerhetspussel.
Kombinera token-autentisering med andra bästa metoder för säkerhet. Kom ihåg att övervaka kontinuerligt och anta konsekventa säkerhetsrutiner; du kommer att avsevärt förbättra den övergripande säkerheten för dina Flask-applikationer.