socialgekon.com
  • Principal
  • Pessoas E Equipes
  • Nutrição
  • Ascensão Do Remoto
  • Ágil
Web Front-End

Tutorial de Django, Flask e Redis: gerenciamento de sessão de aplicativo da Web entre estruturas Python

Django Versus Flask: Quando Django é a escolha errada

Eu amo e uso Django em muitos dos meus projetos pessoais e de clientes, principalmente para aplicações web mais clássicas e aquelas envolvendo bancos de dados relacionais. No entanto, Django não é uma bala de prata.

Por design, Django é fortemente acoplado com seu ORM, Template Engine System e objeto Settings. Além disso, não é um projeto novo: ele carrega muita bagagem para permanecer compatível com as versões anteriores.

Alguns desenvolvedores Python veem isso como um grande problema. Eles dizem que Django não é flexível o suficiente e evite isso se possível e, em vez disso, use um microframework Python como Flask.



Eu não compartilho dessa opinião. Django é ótimo quando usado no lugar e hora apropriados , mesmo que não se encaixe em cada especificações do projeto. Como diz o mantra: “Use a ferramenta certa para o trabalho”.

(Mesmo quando não é o lugar e a hora certos, às vezes programar com Django pode ter benefícios únicos.)

Em alguns casos, pode ser bom usar uma estrutura mais leve (como Frasco ) Freqüentemente, esses microframeworks começam a brilhar quando você percebe como são fáceis de hackear.

Microframeworks to the Rescue

Em alguns dos meus projetos de cliente, discutimos desistir do Django e mudar para um microframework, normalmente quando os clientes querem fazer algo interessante (em um caso, por exemplo, incorporar ZeroMQ no objeto do aplicativo) e os objetivos do projeto parecem mais difíceis de atingir com o Django.

De forma mais geral, acho o Flask útil para:

  • Back-ends simples da API REST
  • Aplicativos que não requerem acesso ao banco de dados
  • Aplicativos da web baseados em NoSQL
  • Aplicativos da web com requisitos muito específicos, como configurações de URL personalizadas

Ao mesmo tempo, nosso aplicativo exigia o registro do usuário e outras tarefas comuns que o Django resolveu anos atrás. Dado seu peso leve, o Flask não vem com o mesmo kit de ferramentas.

A questão surgiu: Django é um negócio tudo ou nada?

A questão surgiu: Django é um negócio tudo ou nada? Devemos largar isso completamente do projeto, ou podemos aprender a combiná-lo com a flexibilidade de outros microframeworks ou frameworks tradicionais? Podemos escolher as peças que queremos usar e evitar outras?

Podemos ter o melhor dos dois mundos? Eu digo que sim, especialmente quando se trata de gerenciamento de sessão.

(Sem mencionar que existem muitos projetos para freelancers de Django.)

Agora, o Tutorial Python: Compartilhando Sessões Django

O objetivo deste post é delegar as tarefas de autenticação e registro do usuário ao Django, e ainda usar o Redis para compartilhar sessões de usuário com outros frameworks. Posso pensar em alguns cenários em que algo assim seria útil:

  • Você precisa desenvolver uma API REST separadamente de seu aplicativo Django, mas deseja compartilhar os dados da sessão.
  • Você tem um componente específico que pode precisar ser substituído posteriormente ou dimensionado por algum motivo e ainda precisa de dados de sessão.

Para este tutorial, vou usar Redis para compartilhar sessões entre dois frameworks (neste caso, Django e Flask). Na configuração atual, vou usar SQLite para armazenar informações do usuário, mas você pode ter seu back-end vinculado a um banco de dados NoSQL (ou uma alternativa baseada em SQL) se necessário.

Sessões de compreensão

Para compartilhar sessões entre Django e Flask, precisamos saber um pouco sobre como o Django armazena suas informações de sessão. o Django docs são muito bons, mas vou fornecer algumas informações básicas para completude.

Variedades de gerenciamento de sessão

Geralmente, você pode optar por gerenciar os dados da sessão do seu aplicativo Python de uma das duas maneiras:

  • Sessões baseadas em cookies : Neste cenário, os dados da sessão não são armazenados em um armazenamento de dados no back-end. Em vez disso, é serializado, assinado (com SECRET_KEY) e enviado ao cliente. Quando o cliente envia os dados de volta, sua integridade é verificada quanto a adulteração e é desserializada novamente no servidor.

  • Sessões baseadas em armazenamento : Neste cenário, os próprios dados da sessão são não enviado ao cliente. Em vez disso, apenas uma pequena parte é enviada (uma chave) para indicar a identidade do usuário atual, armazenada no armazenamento de sessão.

Em nosso exemplo, estamos mais interessados ​​no último cenário: queremos que nossos dados de sessão sejam armazenados no back-end e depois verificados no Flask. A mesma coisa poderia ser feita no anterior, mas como a documentação do Django menciona, existem alguns preocupações com a segurança do primeiro método.

O Fluxo de Trabalho Geral

O fluxo de trabalho geral de manuseio e gerenciamento de sessão será semelhante a este diagrama:

Um diagrama que mostra o gerenciamento de sessões de usuário entre Flask e Django usando Redis.

Vamos examinar o compartilhamento de sessão com mais detalhes:

  1. Quando chega um novo pedido, o primeiro passo é enviá-lo através do cadastro middleware na pilha do Django. Estamos interessados ​​aqui no SessionMiddleware classe que, como você pode esperar, está relacionada ao gerenciamento e tratamento de sessão:

    class SessionMiddleware(object): def process_request(self, request): engine = import_module(settings.SESSION_ENGINE) session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME, None) request.session = engine.SessionStore(session_key)

    Neste trecho, o Django pega o SessionEngine registrado | (chegaremos a isso em breve), extrai o SESSION_COOKIE_NAME de request (sessionid, por padrão) e cria uma nova instância do selecionado SessionEngine para lidar com o armazenamento da sessão.

  • Mais tarde (depois que a visualização do usuário é processada, mas ainda na pilha de middleware), o mecanismo da sessão chama seu método de salvamento para salvar quaisquer alterações no armazenamento de dados. (Durante o tratamento da visualização, o usuário pode ter alterado algumas coisas dentro da sessão, por exemplo, adicionando um novo valor ao objeto de sessão com request.session.) Em seguida, o SESSION_COOKIE_NAME é enviado ao cliente. Esta é a versão simplificada:

    def process_response(self, request, response): .... if response.status_code != 500: request.session.save() response.set_cookie(settings.SESSION_COOKIE_NAME, request.session.session_key, max_age=max_age, expires=expires, domain=settings.SESSION_COOKIE_DOMAIN, path=settings.SESSION_COOKIE_PATH, secure=settings.SESSION_COOKIE_SECURE or None, httponly=settings.SESSION_COOKIE_HTTPONLY or None) return response

Estamos particularmente interessados ​​no SessionEngine classe, que substituiremos por algo para armazenar e carregar dados de e para um back-end do Redis.

Felizmente, existem alguns projetos que já tratam disso para nós. Aqui está um exemplo de redis_sessions_fork . Preste muita atenção ao save e load métodos, que são escritos para (respectivamente) armazenar e carregar a sessão de e para Redis:

class SessionStore(SessionBase): ''' Redis session back-end for Django ''' def __init__(self, session_key=None): super(SessionStore, self).__init__(session_key) def _get_or_create_session_key(self): if self._session_key is None: self._session_key = self._get_new_session_key() return self._session_key def load(self): session_data = backend.get(self.session_key) if not session_data is None: return self.decode(session_data) else: self.create() return {} def exists(self, session_key): return backend.exists(session_key) def create(self): while True: self._session_key = self._get_new_session_key() try: self.save(must_create=True) except CreateError: continue self.modified = True self._session_cache = {} return def save(self, must_create=False): session_key = self._get_or_create_session_key() expire_in = self.get_expiry_age() session_data = self.encode(self._get_session(no_load=must_create)) backend.save(session_key, expire_in, session_data, must_create) def delete(self, session_key=None): if session_key is None: if self.session_key is None: return session_key = self.session_key backend.delete(session_key)

É importante entender como esta classe está operando, pois precisaremos implementar algo semelhante no Flask para carregar os dados da sessão. Vamos dar uma olhada em um exemplo REPL:

>>> from django.conf import settings >>> from django.utils.importlib import import_module >>> engine = import_module(settings.SESSION_ENGINE) >>> engine.SessionStore() >>> store['count'] = 1 >>> store.save() >>> store.load() {u'count': 1}

A interface da loja de sessão é muito fácil de entender, mas há muita coisa acontecendo nos bastidores. Devemos cavar um pouco mais fundo para que possamos implementar algo semelhante no Flask.

Observação: você pode perguntar: “Por que não apenas copiar o SessionEngine para o Flask?” Mais fácil falar do que fazer. Como discutimos no início, Django está fortemente acoplado com seu objeto Settings, então você não pode simplesmente importar algum módulo Django e usá-lo sem qualquer trabalho adicional.

Sessão Django (Des-) Serialização

Como eu disse, o Django faz muito trabalho para mascarar a complexidade de seu armazenamento de sessão. Vamos verificar a chave Redis que está armazenada nos snippets acima:

>>> store.session_key u'ery3j462ezmmgebbpwjajlxjxmvt5adu'

Agora, vamos consultar essa chave no redis-cli:

redis 127.0.0.1:6379> get 'django_sessions:ery3j462ezmmgebbpwjajlxjxmvt5adu' 'ZmUxOTY0ZTFkMmNmODA2OWQ5ZjE4MjNhZmQxNDM0MDBiNmQzNzM2Zjp7ImNvdW50IjoxfQ=='

O que vemos aqui é muito longo, Codificado em Base64 corda. Para entender seu propósito, precisamos olhar para Django SessionBase aula para ver como isso é tratado:

class SessionBase(object): ''' Base class for all Session classes. ''' def encode(self, session_dict): 'Returns the given session dictionary serialized and encoded as a string.' serialized = self.serializer().dumps(session_dict) hash = self._hash(serialized) return base64.b64encode(hash.encode() + b':' + serialized).decode('ascii') def decode(self, session_data): encoded_data = base64.b64decode(force_bytes(session_data)) try: hash, serialized = encoded_data.split(b':', 1) expected_hash = self._hash(serialized) if not constant_time_compare(hash.decode(), expected_hash): raise SuspiciousSession('Session data corrupted') else: return self.serializer().loads(serialized) except Exception as e: # ValueError, SuspiciousOperation, unpickling exceptions if isinstance(e, SuspiciousOperation): logger = logging.getLogger('django.security.%s' % e.__class__.__name__) logger.warning(force_text(e)) return {}

O método encode primeiro serializa os dados com o serializador registrado atual. Em outras palavras, ele converte a sessão em uma string, que mais tarde pode converter de volta em uma sessão (consulte a documentação SESSION_SERIALIZER para mais informações). Em seguida, ele faz o hash dos dados serializados e usa esse hash posteriormente como uma assinatura para verificar a integridade dos dados da sessão. Finalmente, ele retorna esse par de dados ao usuário como uma string codificada em Base64.

A propósito: antes da versão 1.6, o Django padronizou o uso de pickle para serialização de dados de sessão. Devido a preocupações com segurança , o método de serialização padrão agora é django.contrib.sessions.serializers.JSONSerializer.

Codificando uma sessão de exemplo

Vamos ver o processo de gerenciamento de sessão em ação. Aqui, nosso dicionário de sessão será simplesmente uma contagem e algum inteiro, mas você pode imaginar como isso generalizaria para sessões de usuário mais complicadas.

>>> store.encode({'count': 1}) u'ZmUxOTY0ZTFkMmNmODA2OWQ5ZjE4MjNhZmQxNDM0MDBiNmQzNzM2Zjp7ImNvdW50IjoxfQ==' >>> base64.b64decode(encoded) 'fe1964e1d2cf8069d9f1823afd143400b6d3736f:{'count':1}'

O resultado do método de armazenamento (u’ZmUxOTY… == ’) é uma string codificada contendo a sessão de usuário serializada e seu hash. Quando o decodificamos, realmente obtemos de volta o hash (‘fe1964e…’) e a sessão ({'count':1}).

Observe que o método de decodificação verifica se o hash está correto para aquela sessão, garantindo a integridade dos dados quando formos usá-los no Flask. Em nosso caso, não estamos muito preocupados que nossa sessão seja adulterada do lado do cliente porque:

  • Não estamos usando sessões baseadas em cookies, ou seja, não estamos enviando todos dados do usuário para o cliente.

  • No Flask, precisaremos de um SessionStore somente leitura | que nos dirá se dada chave existe ou não e retornará os dados armazenados.

Extensão para Frasco

A seguir, vamos criar uma versão simplificada do mecanismo de sessão Redis (banco de dados) para trabalhar com o Flask. Usaremos o mesmo SessionStore (definido acima) como uma classe base, mas precisaremos remover algumas de suas funcionalidades, por exemplo, verificar assinaturas incorretas ou modificar sessões. Estamos mais interessados ​​em um SessionStore que irá carregar os dados da sessão salvos do Django. Vamos ver como isso funciona:

class SessionStore(object): # The default serializer, for now def __init__(self, conn, session_key, secret, serializer=None): self._conn = conn self.session_key = session_key self._secret = secret self.serializer = serializer or JSONSerializer def load(self): session_data = self._conn.get(self.session_key) if not session_data is None: return self._decode(session_data) else: return {} def exists(self, session_key): return self._conn.exists(session_key) def _decode(self, session_data): ''' Decodes the Django session :param session_data: :return: decoded data ''' encoded_data = base64.b64decode(force_bytes(session_data)) try: # Could produce ValueError if there is no ':' hash, serialized = encoded_data.split(b':', 1) # In the Django version of that they check for corrupted data # I don't find it useful, so I'm removing it return self.serializer().loads(serialized) except Exception as e: # ValueError, SuspiciousOperation, unpickling exceptions. If any of # these happen, return an empty dictionary (i.e., empty session). return {}

Precisamos apenas do load método porque é uma implementação somente leitura do armazenamento. Isso significa que você não pode sair diretamente do Flask; em vez disso, você pode querer redirecionar esta tarefa para Django. Lembre-se, o objetivo aqui é gerenciar sessões entre essas duas estruturas Python para dar a você mais flexibilidade.

Sessões de frasco

O microframework Flask suporta sessões baseadas em cookies, o que significa que todos os dados da sessão são enviados ao cliente, codificados em Base64 e assinados criptograficamente. Mas, na verdade, não estamos muito interessados ​​no suporte de sessão do Flask.

O que precisamos é obter o ID da sessão criado pelo Django e compará-lo com o back-end do Redis para que possamos ter certeza de que a solicitação pertence a um usuário pré-assinado. Em resumo, o processo ideal seria (isso se sincroniza com o diagrama acima):

  • Pegamos o ID da sessão Django do cookie do usuário.
  • Se o ID da sessão for encontrado no Redis, retornamos a sessão correspondente a esse ID.
  • Caso contrário, nós os redirecionamos para uma página de login.

Será útil ter um decorador para verificar essas informações e definir o atual user_id no g variável no Flask:

from functools import wraps from flask import g, request, redirect, url_for def login_required(f): @wraps(f) def decorated_function(*args, **kwargs): djsession_id = request.cookies.get('sessionid') if djsession_id is None: return redirect('/') key = get_session_prefixed(djsession_id) session_store = SessionStore(redis_conn, key) auth = session_store.load() if not auth: return redirect('/') g.user_id = str(auth.get('_auth_user_id')) return f(*args, **kwargs) return decorated_function

No exemplo acima, ainda estamos usando SessionStore definimos anteriormente para buscar os dados do Django do Redis. Se a sessão tiver um _auth_user_id, retornamos o conteúdo da função view; caso contrário, o usuário é redirecionado para uma página de login, como queríamos.

Colando Coisas Juntas

Para compartilhar cookies, acho conveniente iniciar o Django e o Flask por meio de um WSGI servidor e cole-os. Neste exemplo, usei CherryPy :

from app import app from django.core.wsgi import get_wsgi_application application = get_wsgi_application() d = wsgiserver.WSGIPathInfoDispatcher({ '/':application, '/backend':app }) server = wsgiserver.CherryPyWSGIServer(('127.0.0.1', 8080), d)

Com isso, Django servirá em “/” e o Flask servirá em endpoints “/ backend”.

Em conclusão

Em vez de examinar Django versus Flask ou encorajá-lo apenas a aprender o microframework Flask, juntei Django e Flask, fazendo com que compartilhassem os mesmos dados de sessão para autenticação delegando a tarefa ao Django. Como o Django vem com muitos módulos para resolver o registro do usuário, login e logout (apenas para citar alguns), a combinação desses dois frameworks economizará um tempo valioso, enquanto fornece a oportunidade de hackear um microframework gerenciável como o Flask.

Erupção do vulcão na Indonésia: Merapi ejeta nova nuvem de cinzas

Mundo

Erupção do vulcão na Indonésia: Merapi ejeta nova nuvem de cinzas
Mohenjo Daro: Ashutosh Gowariker, por que seus personagens estão chamando sua cidade de 'monte dos mortos'?

Mohenjo Daro: Ashutosh Gowariker, por que seus personagens estão chamando sua cidade de 'monte dos mortos'?

Pesquisar

Publicações Populares
Trudeau do Canadá, perdendo nas pesquisas, defende a convocação das eleições antecipadas
Trudeau do Canadá, perdendo nas pesquisas, defende a convocação das eleições antecipadas
‘Madrasas têm que encontrar um equilíbrio entre o sagrado e o secular ... este último não pode ser uma reflexão tardia na educação’
‘Madrasas têm que encontrar um equilíbrio entre o sagrado e o secular ... este último não pode ser uma reflexão tardia na educação’
Um tutorial passo a passo para seu primeiro aplicativo AngularJS
Um tutorial passo a passo para seu primeiro aplicativo AngularJS
Um processo de 5 etapas para transformar seu blog em um túnel de alta conversão
Um processo de 5 etapas para transformar seu blog em um túnel de alta conversão
Prêmio Nobel de Química de 2021 concedido a Benjamin List e David MacMillan
Prêmio Nobel de Química de 2021 concedido a Benjamin List e David MacMillan
 
IA descomplicada para seu aplicativo: Conheça o Salesforce Einstein
IA descomplicada para seu aplicativo: Conheça o Salesforce Einstein
Introdução ao PHP 7: O que há de novo e o que aconteceu
Introdução ao PHP 7: O que há de novo e o que aconteceu
Guia de um trabalhador remoto para se manter saudável
Guia de um trabalhador remoto para se manter saudável
O código aberto está aberto para mulheres?
O código aberto está aberto para mulheres?
Dicas de design e práticas recomendadas de experiência do usuário da Shopify
Dicas de design e práticas recomendadas de experiência do usuário da Shopify
Categorias
FilmagemDesign MóvelVida DesignerPlanejamento E PrevisãoProcessos FinanceirosAméricasDesign De IuReceita E CrescimentoPessoas E EquipesÁsia

© 2023 | Todos Os Direitos Reservados

socialgekon.com