Ciência e Tecnologia

Como implementar autenticação de usuário no Flask usando JWT

.

A autenticação quebrada continua a ser uma vulnerabilidade persistente em aplicativos da Web modernos – ela ainda está classificada entre os 10 principais riscos de segurança de API do OWASP.



vídeo do dia

Innocn 48Q1V: imersão definitiva em jogos neste monstro de 48″ O Innocn 48Q1V é um monitor de jogos maior, mais rápido e com melhor som que você pode comprar em 2023.


Os efeitos dessa vulnerabilidade podem ser graves. Eles podem conceder acesso não autorizado a dados confidenciais e comprometer a integridade do sistema. Para garantir de forma eficaz o acesso seguro aos aplicativos e seus recursos, é vital que você use mecanismos de autenticação robustos.

Descubra como você pode implementar a autenticação do usuário no Flask usando JSON Web Tokens (JWT), um método baseado em token popular e eficaz.



Autenticação baseada em token usando tokens Web JSON

A autenticação baseada em token usa uma sequência criptografada de caracteres para validar e autorizar o acesso a um sistema ou recurso. Você pode implementar esse tipo de autenticação usando vários métodos, incluindo tokens de sessão, chaves de API e JSON Web Tokens.

Os JWTs, em particular, oferecem uma abordagem segura e compacta para transmitir as credenciais de usuários necessárias entre aplicativos e servidores do lado do cliente.

Um exemplo de um token JWT codificado no lado esquerdo e a versão decodificada do token mostrando componentes individuais no lado direito.

Um JWT consiste em três componentes principais: o cabeçalho, a carga útil e a assinatura. O cabeçalho contém metadados sobre o token, incluindo o algoritmo de hash usado para codificar o token.

A carga útil contém as credenciais reais do usuário, como ID do usuário e permissões. Por fim, a assinatura garante a validade do token verificando seu conteúdo por meio de uma chave secreta.

Usando JWTs, você pode autenticar usuários e armazenar dados de sessão dentro do próprio token.

Configurar um projeto Flask e um banco de dados MongoDB

Para começar, crie um novo diretório de projeto usando um terminal:

 mkdir flask-project
cd flask-project

Em seguida, instale virtualenvpara criar um ambiente de desenvolvimento virtual local para seu projeto Flask.

 virtualenv venv 

Por fim, ative o ambiente virtual.

 # Unix or MacOS: 
source venv/bin/activate

# Windows:
.venvScriptsactivate

Instale os pacotes necessários

No diretório raiz da pasta do seu projeto, crie um novo requisitos.txt arquivo e adicione estas dependências para o projeto:

 flask
pyjwt
python-dotenv
pymongo
bcrypt

Por fim, execute o comando abaixo para instalar os pacotes. Assegure-se de ter pip (gerenciador de pacotes) instalado; caso contrário, instale-o em seu sistema Windows, Mac ou Linux.

 pip install -r requirements.txt 

Criar um banco de dados MongoDB

Vá em frente e crie um banco de dados MongoDB. Você pode configurar um banco de dados MongoDB local, como alternativa, criar um cluster no MongoDB Atlas, um serviço MongoDB baseado em nuvem.

Depois de criar o banco de dados, copie o URI de conexão, crie um .env arquivo no diretório raiz do seu projeto e adicione-o da seguinte maneira:

 MONGO_URI="<insert-connection-uri>" 

Por fim, configure a conexão com o banco de dados de seu aplicativo Flask. Crie um novo utils/db.py arquivo no diretório raiz do seu projeto, com este código:

 from pymongo import MongoClient

def connect_to_mongodb(mongo_uri):
    client = MongoClient(mongo_uri)
    db = client.get_database("users")
    return db

Esta função estabelece uma conexão com o banco de dados MongoDB usando o URI de conexão fornecido. Em seguida, cria um novo Usuários coleção se não existir e retorna a instância de banco de dados correspondente.

Criar o Servidor Web Flask

Com o banco de dados configurado, vá em frente e crie um app.py arquivo no diretório raiz da pasta do projeto e adicione o código a seguir para criar uma instância do aplicativo Flask.

 from flask import Flask
from routes.user_auth import register_routes
from utils.db import connect_to_mongodb
import os
from dotenv import load_dotenv

app = Flask(__name__)
load_dotenv()

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

register_routes(app, db)

if __name__ == '__main__':
    app.run(debug=True)

Crie os endpoints da API de autenticação

Para implementar a autenticação do usuário em seu aplicativo Flask, é crucial definir os endpoints de API necessários que lidam com operações relacionadas à autenticação.

No entanto, primeiro defina o modelo para os dados dos usuários. Para isso, crie um novo model/user_model.py arquivo no diretório raiz e adicione o código a seguir.

 from pymongo.collection import Collection
from bson.objectid import ObjectId

class User:
    def __init__(self, collection: Collection, username: str, password: str):
        self.collection = collection
        self.username = username
        self.password = password
    def save(self):
        user_data = {
            'username': self.username,
            'password': self.password
        }
        result = self.collection.insert_one(user_data)
        return str(result.inserted_id)

@staticmethod
    def find_by_id(collection: Collection, user_id: str):
        return collection.find_one({'_id': ObjectId(user_id)})

@staticmethod
    def find_by_username(collection: Collection, username: str):
        return collection.find_one({'username': username})

O código acima especifica um Do utilizador classe que serve como um modelo de dados e define vários métodos para interagir com uma coleção do MongoDB para executar operações relacionadas ao usuário.

  1. O salvar O método salva um novo documento do usuário com o nome de usuário e a senha fornecidos para a coleção do MongoDB e retorna o ID do documento inserido.
  2. O encontrar_por_id e find_by_username Os métodos recuperam documentos do usuário da coleção com base no ID do usuário ou nome de usuário fornecido, respectivamente.

Definir as Rotas de Autenticação

  1. Vamos começar definindo a rota de registro. Essa rota adicionará novos dados do usuário à coleção de usuários do MongoDB. No diretório raiz, crie um novo rotas/user_auth.py arquivo e o seguinte código.
     import jwt
    from functools import wraps
    from flask import jsonify, request, make_response
    from models.user_model import User
    import bcrypt
    import os

    def register_routes(app, db):
        collection = db.users
        app.config['SECRET_KEY'] = os.urandom(24)

    @app.route('/api/register', methods=['POST'])
        def register():
            
            username = request.json.get('username')
            password = request.json.get('password')
            
            existing_user = User.find_by_username(collection, username)
            if existing_user:
                return jsonify({'message': 'Username already exists!'})
          
            hashed_password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt())
            new_user = User(collection, username, hashed_password.decode('utf-8'))
            user_id = new_user.save()

            return jsonify({'message': 'User registered successfully!', 'user_id': user_id})

  2. Implemente a funcionalidade de login para lidar com o processo de autenticação e verificar as credenciais do usuário. Na rota de registro, adicione o seguinte código.
      @app.route('/api/login', methods=['POST'])
        def login():
            username = request.json.get('username')
            password = request.json.get('password')
            user = User.find_by_username(collection, username)
            if user:
                if bcrypt.checkpw(password.encode('utf-8'), user['password'].encode('utf-8')):
                    token = jwt.encode({'user_id': str(user['_id'])}, app.config['SECRET_KEY'], algorithm='HS256')
              
                    response = make_response(jsonify({'message': 'Login successful!'}))
                    response.set_cookie('token', token)
                    return response

            return jsonify({'message': 'Invalid username or password'})

    O endpoint de login faz duas coisas: verifica as credenciais de usuário fornecidas e, após a autenticação bem-sucedida, gera um JWT exclusivo para esse usuário. Ele define esse token como um cookie na resposta, junto com uma carga JSON indicando um login bem-sucedido. Se as credenciais forem inválidas, ele retornará uma resposta JSON para indicar isso.

  3. Defina uma função de decorador que verifique os JSON Web Tokens (JWTs) transmitidos junto com as solicitações de API subsequentes. Adicione o código abaixo dentro do register_routes bloco de código de função.
         def token_required(f):
    @wraps(f)
            def decorated(*args, **kwargs):
                token = request.cookies.get('token')

                if not token:
                    return jsonify({'message': 'Token is missing!'}), 401

                try:
                    data = jwt.decode(token, app.config['SECRET_KEY'], algorithms=['HS256'])
                    current_user = User.find_by_id(collection, data['user_id'])
                except jwt.ExpiredSignatureError:
                    return jsonify({'message': 'Token has expired!'}), 401
                except jwt.InvalidTokenError:
                    return jsonify({'message': 'Invalid token!'}), 401

                return f(current_user, *args, **kwargs)

            return decorated

    Essa função de decorador garante a presença de um token JWT válido em solicitações de API subsequentes. Ele verifica se o token está ausente, expirado ou válido e retorna uma resposta JSON apropriada, se estiver.

  4. Finalmente, crie uma rota protegida.
      @app.route('/api/users', methods=['GET'])
    @token_required
        def get_users(current_user):
            users = list(collection.find({}, {'_id': 0}))
            return jsonify(users)

Esse ponto de extremidade manipula a lógica para recuperar dados do usuário do banco de dados, mas requer que o cliente que envia solicitações inclua um token válido para acessar os dados.

Por fim, execute o comando abaixo para ativar o servidor de desenvolvimento.

 flask run 

Para testar o registro, o login e o endpoint dos usuários protegidos, você pode usar o Postman ou qualquer outro cliente API. Enviar pedidos para http://localhost:5000/api/ e observe as respostas para verificar a funcionalidade desses endpoints da API.

A autenticação de token é uma medida de segurança infalível?

Os JSON Web Tokens fornecem uma maneira robusta e eficaz de autenticar usuários para seu aplicativo da web. No entanto, é importante entender que a autenticação de token não é infalível; é apenas uma peça de um quebra-cabeça de segurança maior.

Combine autenticação de token com outras práticas recomendadas de segurança. Lembre-se de monitorar continuamente e adotar práticas de segurança consistentes; você aumentará significativamente a segurança geral de seus aplicativos Flask.

.

Mostrar mais

Artigos relacionados

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Botão Voltar ao topo