Você está na página 1de 16

Aluno: Fabrício Rodrigues Farias.

Pesquisar experimento Prático em SD

1 - Ambiente Heterogêneo.
Um exemplo de ambiente heterogêneo seria um sistema distribuído composto por
dois servidores: um rodando no sistema operacional Windows e outro no sistema
operacional Linux. Cada servidor possui uma aplicação escrita em uma linguagem
de programação diferente (Python e Java, respectivamente) e se comunicam
usando diferentes protocolos de rede.
Para fazer com que esses sistemas possam se comunicar e trocar informações, é
necessário estabelecer um padrão comum para a comunicação e utilizar um
protocolo de rede que seja compreendido pelos dois sistemas. Uma solução para
isso seria utilizar o protocolo HTTP, que é amplamente utilizado em ambientes
distribuídos e possui suporte tanto em Python quanto em Java.
Exemplo em Python de como é possível realizar uma comunicação entre um
servidor Python e um servidor Java, ambos em sistemas operacionais diferentes,
utilizando o protocolo HTTP:

import requests

# Define a URL do servidor Java


url = "http://<endereco_do_servidor_java>:8080/"

# Define o conteúdo da requisição em formato JSON


payload = {"mensagem": "Olá, mundo!"}

# Realiza uma requisição HTTP POST para o servidor Java


response = requests.post(url, json=payload)

# Exibe a resposta do servidor Java


print(response.content)

Nesse exemplo, o servidor Python utiliza a biblioteca Requests para realizar uma
requisição HTTP POST para o servidor Java, passando um objeto JSON como
conteúdo da requisição. O servidor Java, por sua vez, deve estar preparado para
receber requisições nesse formato e processá-las corretamente.
Em resumo, a interoperabilidade em ambientes heterogêneos é alcançada por meio
do uso de padrões comuns de comunicação e protocolos de rede que sejam
compreendidos por todos os sistemas envolvidos. O exemplo em Python ilustra
como é possível fazer isso na prática, permitindo que sistemas escritos em
linguagens de programação diferentes e rodando em sistemas operacionais
diferentes possam se comunicar e trocar informações de forma transparente.
2 - Middleware CORBA
Suponha que temos um sistema distribuído composto por dois componentes: um
cliente e um servidor. O cliente precisa enviar uma mensagem para o servidor, que
deve processá-la e retornar uma resposta.
Para permitir essa comunicação, podemos utilizar a tecnologia CORBA. Primeiro,
devemos definir a interface dos objetos utilizando a IDL:

module exemplo {
interface Servidor {
string processaMensagem(in string mensagem);
};
};

Essa IDL define uma interface chamada Servidor que possui um método chamado
processaMensagem que recebe uma string como parâmetro de entrada e retorna
uma string como resultado.
Em seguida, utilizamos o compilador idlj para gerar o código necessário para
implementar essa interface em Python:

idlj -fall exemplo.idl

Esse comando gera um conjunto de arquivos Python que implementam a interface


Servidor, incluindo um arquivo chamado exemplo__POA.py que contém a
implementação do servidor.
Para executar o servidor, basta executar o arquivo exemplo__POA.py:

from exemplo import Servidor, ServidorHelper


from omniORB import CORBA, PortableServer

class ServidorImpl(Servidor):
def processaMensagem(self, mensagem):
return "Mensagem recebida: {}".format(mensagem)

orb = CORBA.ORB_init()
poa = orb.resolve_initial_references("RootPOA")
servant = ServidorImpl()
objref = poa.servant_to_reference(servant)
ior = orb.object_to_string(objref)

with open("ior.txt", "w") as f:


f.write(ior)

poa._get_the_POAManager().activate()
orb.run()

Esse código define uma classe ServidorImpl que implementa a interface Servidor e
sobrescreve o método processaMensagem para retornar a mensagem recebida pelo
servidor. Em seguida, ele utiliza o ORB para registrar o objeto ServidorImpl e gerar
uma representação do objeto (IOR - Interoperable Object Reference) que é gravada
em um arquivo chamado ior.txt.
Para executar o cliente, basta utilizar o arquivo exemplo.py gerado pelo compilador
idlj:

from exemplo import Servidor, ServidorHelper


from omniORB import CORBA

orb = CORBA.ORB_init()
with open("ior.txt", "r") as f:
ior = f.read()

objref = orb.string_to_object(ior)
servidor = ServidorHelper.narrow(objref)

mensagem = "Olá, mundo!"


resultado = servidor.processaMensagem(mensagem)
print(resultado)

Esse código utiliza o ORB para obter uma referência ao objeto Servidor a partir da
representação (IOR) gravada no arquivo ior.txt. Em seguida, ele utiliza o objeto
Servidor para chamar o método processaMensagem com a mensagem desejada e
exibir o resultado.
Para executar esse exemplo na prática, é necessário instalar o pacote omniORB
para Python:

pip install omniORB

Em seguida, crie um arquivo servidor.py com a implementação do servidor


apresentada acima e execute-o em um terminal:

python servidor.py
Esse comando iniciará o servidor, que ficará aguardando conexões de clientes.
Por fim, crie um arquivo cliente.py com a implementação do cliente apresentada
acima e execute-o em outro terminal:

python cliente.py

Esse comando executará o cliente, que se conectará ao servidor, enviará uma

mensagem e exibirá o resultado.É importante ressaltar que a configuração e o uso

de um middleware podem ser mais complexos em sistemas reais, mas a ideia

básica é a mesma: utilizar uma camada de software para permitir a comunicação

entre diferentes sistemas ou componentes de forma transparente.

3 - Concorrência
Concorrência é a capacidade de executar múltiplas tarefas simultaneamente em um
sistema computacional. Existem várias técnicas para implementar concorrência em
um programa, como threads, processos, eventos, entre outros.
Um exemplo teórico de implementação de concorrência pode ser a criação de um
programa que executa duas tarefas simultaneamente: uma tarefa que lê um arquivo
e outra que escreve em um arquivo. Para isso, podemos utilizar threads para
executar essas duas tarefas em paralelo.
Suponha que temos um arquivo chamado dados.txt que contém uma lista de
números inteiros separados por vírgulas. Queremos ler esse arquivo e calcular a
média dos números lidos, e ao mesmo tempo escrever essa média em um arquivo
chamado resultado.txt.
Podemos implementar esse programa utilizando threads da seguinte forma:

import threading

class LeitorThread(threading.Thread):
def __init__(self, arquivo):
threading.Thread.__init__(self)
self.arquivo = arquivo

def run(self):
with open(self.arquivo, 'r') as f:
numeros = [int(num) for num in f.read().split(',')]
media = sum(numeros) / len(numeros)
EscritorThread(media).start()
class EscritorThread(threading.Thread):
def __init__(self, media):
threading.Thread.__init__(self)
self.media = media

def run(self):
with open('resultado.txt', 'w') as f:
f.write(str(self.media))

LeitorThread('dados.txt').start()

Nesse exemplo, a classe LeitorThread é responsável por ler os dados do arquivo e


calcular a média dos números, e a classe EscritorThread é responsável por escrever
a média em um arquivo. A classe LeitorThread é iniciada com o nome do arquivo
que deve ser lido. Dentro do método run dessa classe, o arquivo é aberto e lido, os
números são calculados e a média é passada como parâmetro para uma nova
instância da classe EscritorThread. Essa nova instância é iniciada com a média
calculada e, dentro do método run, a média é escrita no arquivo.
Por fim, a classe LeitorThread é iniciada e o programa é executado em duas
threads: uma thread que lê o arquivo e outra thread que escreve a média no
arquivo.
Crie um arquivo chamado dados.txt com uma lista de números inteiros separados
por vírgulas. Por exemplo:

1,2,3,4,5

Em seguida, crie um arquivo chamado concorrencia.py com o código apresentado


acima e execute-o em um terminal:

python concorrencia.py

Esse comando iniciará o programa, que lerá o arquivo dados.txt, calculará a média
dos números lidos e escreverá essa média no arquivo resultado.txt.

4 - Compartilhamento de recursos
Compartilhamento de recursos é a prática de permitir que múltiplos processos ou
threads acessem um recurso compartilhado, como um arquivo ou um banco de
dados, ao mesmo tempo. O compartilhamento de recursos pode melhorar a
eficiência e a escalabilidade do sistema, mas também pode introduzir problemas de
concorrência.
Um exemplo teórico de implementação de compartilhamento de recursos pode ser a
criação de um programa que permite que múltiplos usuários acessem um arquivo de
texto compartilhado. Nesse caso, cada usuário teria sua própria thread e todas as
threads teriam acesso ao mesmo arquivo de texto.
Para implementar esse programa, seria necessário usar mecanismos de
sincronização para garantir que as threads não tentem escrever no arquivo ao
mesmo tempo. Além disso, seria necessário implementar uma forma de garantir que
as alterações feitas por uma thread sejam refletidas para todas as outras threads.
Um exemplo prático de implementação de compartilhamento de recursos pode ser a
criação de um programa que permite que múltiplos usuários editem um arquivo de
texto compartilhado. Para isso, podemos utilizar o módulo threading do Python para
criar uma thread para cada usuário.

import threading

class TextoCompartilhado:
def __init__(self):
self.texto = ''
self.lock = threading.Lock()

def adicionar_texto(self, texto):


with self.lock:
self.texto += texto

def obter_texto(self):
with self.lock:
return self.texto

class Usuario:
def __init__(self, nome, texto_compartilhado):
self.nome = nome
self.texto_compartilhado = texto_compartilhado

def editar_texto(self, texto):


self.texto_compartilhado.adicionar_texto('{}: {}\n'.format(self.nome,
texto))

texto_compartilhado = TextoCompartilhado()

Usuario('Usuario1', texto_compartilhado).editar_texto('Olá, mundo!')


Usuario('Usuario2', texto_compartilhado).editar_texto('Olá, todos!')

print(texto_compartilhado.obter_texto())

Nesse exemplo, a classe TextoCompartilhado é responsável por armazenar o texto


compartilhado e garantir que as operações de leitura e escrita sejam realizadas de
forma segura, utilizando um objeto de trava (lock). A classe Usuario é responsável
por editar o texto compartilhado.
No exemplo, criamos uma instância da classe TextoCompartilhado e duas instâncias
da classe Usuario, cada uma com seu próprio nome. Em seguida, cada usuário
chama o método editar_texto da classe Usuario, passando uma string que deve ser
adicionada ao texto compartilhado. Por fim, chamamos o método obter_texto da
classe TextoCompartilhado para obter o texto atualizado.
Ao executar esse exemplo, teremos a saída:

Usuario1: Olá, mundo!


Usuario2: Olá, todos!

5 - Disponibilidade
Disponibilidade é a capacidade de um sistema estar sempre em funcionamento e
responder às solicitações dos usuários. Isso significa que, mesmo em caso de
falhas de hardware ou software, o sistema deve continuar funcionando ou ser capaz
de se recuperar rapidamente.
Um exemplo de implementação de disponibilidade pode ser a criação de um
sistema distribuído com redundância de hardware e software. Nesse sistema, os
componentes críticos seriam duplicados em servidores diferentes, e um sistema de
monitoramento seria implementado para detectar falhas e redirecionar o tráfego
para os componentes de backup em caso de problemas.
Um exemplo prático de implementação de disponibilidade pode ser a criação de um
programa que realiza o balanceamento de carga em um cluster de servidores. O
objetivo do balanceamento de carga é distribuir o tráfego entre os servidores
disponíveis de forma equilibrada, evitando que um único servidor fique
sobrecarregado e comprometa a disponibilidade do sistema.
Para implementar esse programa, podemos utilizar a biblioteca flask do Python para
criar uma aplicação web que retorna uma mensagem simples. Em seguida,
podemos utilizar a biblioteca pyinotify para monitorar alterações em um arquivo de
configuração que contém os endereços IP e portas dos servidores disponíveis.

from flask import Flask


import requests
import pyinotify

app = Flask(__name__)

servers = []

class ConfigWatcher(pyinotify.ProcessEvent):
def process_IN_MODIFY(self, event):
global servers
with open(event.pathname) as f:
servers = f.read().strip().split('\n')

wm = pyinotify.WatchManager()
notifier = pyinotify.Notifier(wm, ConfigWatcher())
wm.add_watch('config.txt', pyinotify.IN_MODIFY)

@app.route('/')
def hello():
if not servers:
return 'Nenhum servidor disponível!'
for server in servers:
try:
response = requests.get('http://{}/mensagem'.format(server),
timeout=1)
if response.status_code == 200:
return response.content
except:
pass
return 'Nenhum servidor disponível!'

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

Nesse exemplo, a classe ConfigWatcher é responsável por monitorar o arquivo


config.txt e atualizar a lista de servidores disponíveis sempre que o arquivo for
modificado. A lista de servidores é armazenada em uma variável global chamada
servers.
A função hello é a rota principal da aplicação, que recebe as solicitações dos
usuários e realiza o balanceamento de carga entre os servidores disponíveis. A
função tenta enviar uma solicitação HTTP para cada servidor disponível na lista
servers e retorna a resposta do primeiro servidor que responder com sucesso. Se
nenhum servidor estiver disponível, a função retorna uma mensagem de erro.
Ao ser executado, a aplicação web ficará em execução e o balanceamento de carga
será realizado automaticamente entre os servidores configurados no arquivo
config.txt. Se um servidor ficar inativo ou não responder, o programa
automaticamente direcionará as solicitações para os outros servidores disponíveis,
garantindo a disponibilidade do sistema.

6 - Confiabilidade
Confiabilidade é a capacidade de um sistema de realizar suas funções corretamente
e de forma consistente, mesmo em situações de falhas e erros. Isso envolve a
prevenção de falhas, a detecção e correção de erros, e a recuperação em caso de
falhas. Um exemplo teórico de implementação de confiabilidade pode ser a criação
de um sistema distribuído com redundância de hardware e software, além de
mecanismos de detecção de falhas e recuperação automática. Esse sistema seria
capaz de detectar falhas em componentes individuais e redirecionar o tráfego para
componentes de backup, além de registrar e notificar os usuários sobre as falhas e
erros ocorridos.
Uma implementação de confiabilidade pode ser a criação de um programa que
realiza o backup de arquivos em um sistema de armazenamento distribuído. O
objetivo desse programa é garantir que os arquivos estejam sempre disponíveis,
mesmo em caso de falhas ou erros no sistema de armazenamento.
Para implementar esse programa, podemos utilizar a biblioteca watchdog do Python
para monitorar alterações em um diretório local e a biblioteca boto3 para interagir
com o serviço de armazenamento S3 da Amazon.

import os
import time
import boto3
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler

s3 = boto3.resource('s3')
bucket_name = 'meu-bucket'

class BackupHandler(FileSystemEventHandler):
def on_created(self, event):
upload_file(event.src_path)

def on_modified(self, event):


upload_file(event.src_path)

def on_deleted(self, event):


delete_file(event.src_path)

def upload_file(file_path):
try:
s3.meta.client.upload_file(file_path, bucket_name,
os.path.basename(file_path))
except Exception as e:
print('Erro ao fazer upload do arquivo:', e)

def delete_file(file_path):
try:
s3.Object(bucket_name, os.path.basename(file_path)).delete()
except Exception as e:
print('Erro ao excluir o arquivo:', e)
if __name__ == '__main__':
event_handler = BackupHandler()
observer = Observer()
observer.schedule(event_handler, '.', recursive=True)
observer.start()
print('Realizando backup...')
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
observer.stop()
observer.join()

Nesse exemplo, a classe BackupHandler é responsável por monitorar um diretório


local e realizar as operações de upload e delete de arquivos no serviço S3 da
Amazon. A função upload_file realiza o upload de um arquivo para o bucket
especificado, enquanto a função delete_file exclui um arquivo do bucket.
Ao executar esse exemplo, o programa ficará em execução e realizará
automaticamente o backup dos arquivos sempre que houver alterações no diretório
monitorado. Se ocorrerem erros ou falhas durante o processo de upload ou delete, o
programa registrará o erro na saída padrão. Dessa forma, mesmo em caso de
falhas ou erros, o programa continuará em execução e garantirá a confiabilidade do
sistema de backup de arquivos.

7 - Tolerância a Falhas
A Tolerância a Falhas é a capacidade de um sistema de continuar a operar
corretamente, mesmo quando ocorrem falhas em um ou mais componentes do
sistema. Essa técnica envolve a implementação de mecanismos que permitam a
detecção e correção de falhas, bem como a recuperação do sistema em caso de
falhas irrecuperáveis. Um exemplo teórico de implementação de Tolerância a Falhas
pode ser a criação de um sistema distribuído com redundância de hardware e
software, além de mecanismos de detecção de falhas e recuperação automática.
Esse sistema seria capaz de detectar falhas em componentes individuais e
redirecionar o tráfego para componentes de backup, além de registrar e notificar os
usuários sobre as falhas e erros ocorridos. Um exemplo prático de implementação
de Tolerância a Falhas pode ser a criação de um programa que realiza o download
de arquivos em um sistema de armazenamento distribuído, com a capacidade de
retomar o download caso ocorra uma falha durante o processo.
Para implementar esse programa, podemos utilizar a biblioteca requests do Python
para realizar as operações de download e a biblioteca pickle para serializar e salvar
o estado do download em caso de falhas.

import os
import requests
import pickle

url = 'http://meus-arquivos.com/arquivo.txt'
download_path = 'downloads/arquivo.txt'
state_path = 'state.pickle'

def download_file(url, path):


try:
r = requests.get(url, stream=True)
with open(path, 'wb') as f:
for chunk in r.iter_content(chunk_size=1024):
if chunk:
f.write(chunk)
except Exception as e:
print('Erro ao fazer download do arquivo:', e)
return False
return True

def resume_download(url, path, state_path):


if os.path.exists(state_path):
with open(state_path, 'rb') as f:
state = pickle.load(f)
start_byte = state['byte']
else:
start_byte = 0
headers = {'Range': f'bytes={start_byte}-'}
try:
r = requests.get(url, headers=headers, stream=True)
with open(path, 'ab') as f:
for chunk in r.iter_content(chunk_size=1024):
if chunk:
f.write(chunk)
start_byte += len(chunk)
with open(state_path, 'wb') as state_file:
pickle.dump({'byte': start_byte}, state_file)
except Exception as e:
print('Erro ao fazer download do arquivo:', e)
return False
return True

if __name__ == '__main__':
if os.path.exists(download_path):
resume_download(url, download_path, state_path)
else:
download_file(url, download_path)

Nesse exemplo, a função download_file é responsável por realizar o download de


um arquivo a partir de uma URL, enquanto a função resume_download é
responsável por retomar o download de um arquivo caso ocorra uma falha durante o
processo. A função pickle é utilizada para serializar e salvar o estado do download
em um arquivo, permitindo que o download seja retomado a partir do ponto onde
parou.
Ao executar esse exemplo, o programa verifica se o arquivo a ser baixado já existe
no diretório especificado. Se o arquivo existir, o programa retoma o download a
partir do ponto em que parou usando a função resume_download. Caso contrário, o
programa inicia um novo download usando a função download_file.
Com essa implementação, o programa é capaz de tolerar falhas durante o processo
de download, permitindo que o download seja retomado a partir do ponto em que
parou caso ocorra uma falha na conexão ou no sistema de armazenamento
distribuído.
É importante ressaltar que a Tolerância a Falhas não é uma técnica que pode
eliminar completamente as falhas em um sistema. Em vez disso, ela é uma
abordagem que permite que um sistema continue a operar corretamente mesmo
quando ocorrem falhas. Por isso, é importante avaliar cuidadosamente as
necessidades de tolerância a falhas de um sistema e implementar as técnicas
adequadas para garantir a sua confiabilidade e disponibilidade.

8 - Escalabilidade
Escalabilidade é a capacidade de um sistema lidar com um aumento na demanda
de recursos e usuários sem degradar seu desempenho. A seguir, apresentamos um
exemplo simples de implementação de escalabilidade de forma teórica e prática.

Exemplo teórico
Suponha que temos um sistema de comércio eletrônico que está experimentando
um aumento no número de usuários e pedidos. Para lidar com o aumento de
demanda, podemos implementar escalabilidade horizontal, que envolve a adição de
mais instâncias de um componente em execução em várias máquinas.
Para implementar a escalabilidade horizontal, podemos usar um balanceador de
carga que distribui o tráfego entre as várias instâncias do componente. Quando a
carga no sistema aumenta, podemos adicionar mais instâncias do componente para
lidar com o aumento na demanda. O balanceador de carga pode detectar
automaticamente a adição de novas instâncias e distribuir o tráfego de forma
adequada.
Exemplo prático em Python
A seguir, apresentamos um exemplo simples de implementação de escalabilidade
horizontal em um sistema web usando Python e o framework Flask. Suponha que
temos uma aplicação web que processa pedidos de um sistema de comércio
eletrônico. A aplicação é composta por um componente que recebe pedidos e um
banco de dados que armazena informações sobre os pedidos.
Para implementar a escalabilidade horizontal, podemos usar o servidor web
Gunicorn, que é capaz de executar múltiplas instâncias da nossa aplicação Flask
em diferentes processos. O Gunicorn é um servidor WSGI (Web Server Gateway
Interface) que suporta a execução de várias instâncias de uma aplicação Python em
paralelo.
Para instalar o Gunicorn, podemos usar o seguinte comando:

pip install gunicorn

A seguir, criamos um arquivo app.py que contém a nossa aplicação Flask:

from flask import Flask

app = Flask(__name__)

@app.route('/')
def index():
return 'Hello, world!'

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

A aplicação consiste em uma rota raiz que retorna uma mensagem "Hello, world!"
quando é acessada.
Para executar a nossa aplicação com o Gunicorn, podemos usar o seguinte
comando:

gunicorn app:app -w 4

Este comando inicia o servidor Gunicorn com quatro instâncias da nossa aplicação
Flask em execução em diferentes processos. O Gunicorn também gerencia
automaticamente o balanceamento de carga entre as instâncias, distribuindo as
solicitações de forma equilibrada.
Com essa implementação, podemos aumentar o número de instâncias da aplicação
conforme necessário para lidar com o aumento na demanda. O Gunicorn também
garante que a aplicação continue a ser executada mesmo se uma das instâncias
falhar.
9 - Segurança
A segurança é uma preocupação importante em sistemas distribuídos, pois os
dados e informações transmitidos entre diferentes componentes e sistemas podem
estar expostos a ameaças externas. A seguir, apresentamos um exemplo simples
de implementação de segurança de forma teórica e prática.

Suponha que temos um sistema de armazenamento distribuído que é acessado por


diferentes usuários em uma rede. Para garantir a segurança dos dados
armazenados, podemos implementar uma série de medidas de segurança, como
autenticação de usuários, criptografia de dados, controle de acesso e
monitoramento de atividades.
A autenticação de usuários envolve a verificação da identidade de um usuário que
tenta acessar o sistema. Podemos implementar a autenticação usando senhas,
chaves de autenticação ou outros mecanismos de autenticação, como tokens de
segurança.
A criptografia de dados envolve a codificação dos dados antes de serem
transmitidos pela rede, garantindo que os dados só possam ser lidos por usuários
autorizados. Podemos implementar a criptografia usando algoritmos criptográficos,
como AES (Advanced Encryption Standard) ou RSA (Rivest-Shamir-Adleman).
O controle de acesso envolve a definição de políticas que determinam quem pode
acessar quais dados ou recursos em um sistema. Podemos implementar o controle
de acesso usando listas de controle de acesso (ACLs) ou mecanismos baseados
em funções (RBAC).
O monitoramento de atividades envolve a coleta de informações sobre as atividades
dos usuários no sistema, permitindo que os administradores detectem possíveis
ameaças e monitorem o desempenho do sistema. Podemos implementar o
monitoramento usando ferramentas de log e análise de dados.
Exemplo simples de implementação de segurança em um sistema distribuído
usando Python e o framework Flask. Suponha que temos uma aplicação web que
armazena informações confidenciais sobre clientes e que deve ser acessada
apenas por usuários autenticados.
Para implementar a autenticação, podemos usar a extensão Flask-Login, que
fornece uma maneira fácil de gerenciar sessões de usuário em uma aplicação Flask.
A extensão permite que os usuários se autentiquem com um nome de usuário e
senha, mantendo uma sessão de usuário ativa enquanto o usuário estiver
conectado.
Para instalar o Flask-Login, podemos usar o seguinte comando:

pip install flask-login

A seguir, criamos um arquivo app.py que contém a nossa aplicação Flask:


from flask import Flask, render_template, redirect, url_for
from flask_login import LoginManager, login_user, current_user,
login_required, logout_user

app = Flask(__name__)
app.secret_key = 'sua_chave_secreta_aqui'

login_manager = LoginManager(app)

users = {
'alice': {'password': 'password'},
'bob': {'password': 'password'}
}

class User:
def __init__(self, username):
self.username = username

def is_authenticated(self):
return True

def is_active(self):
return True

def is_anonymous(self):
return False

def get_id(self):
return self.username

@login_manager.user_loader
def load_user(user_id):
if user_id in users:
return User(user_id)
return None

@app.route('/')
@login_required
def index():
return render_template('index.html')

@app.route('/login', methods=['GET', 'POST'])


def login():
if current_user.is_authenticated:
return redirect(url_for('index'))

if request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')

if username in users and users[username]['password'] == password:


user = User(username)
login_user(user)
return redirect(url_for('index'))

flash('Invalid username or password')

return render_template('login.html')

@app.route('/logout')
@login_required
def logout():
logout_user()
return redirect(url_for('index'))

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

Neste exemplo, criamos uma aplicação Flask que possui três rotas principais:
● A rota raiz, que só pode ser acessada por usuários autenticados. Caso um
usuário não autenticado tente acessar essa rota, ele será redirecionado para
a página de login.
● A rota /login, que exibe um formulário de login. Se um usuário inserir um
nome de usuário e senha válidos, ele será autenticado e redirecionado para a
página inicial. Caso contrário, uma mensagem de erro será exibida.
● A rota /logout, que permite que os usuários saiam da sessão.
Para autenticar os usuários, criamos uma classe User que implementa as funções
is_authenticated, is_active, is_anonymous e get_id, conforme requerido pela
extensão Flask-Login. Além disso, definimos uma função load_user que retorna uma
instância da classe User com base no ID do usuário fornecido. Na rota /login,
verificamos se o nome de usuário e a senha inseridos correspondem a um usuário
válido no dicionário users e, se for o caso, autenticamos o usuário usando a função
login_user da extensão Flask-Login.

Você também pode gostar