socialgekon.com
  • Tärkein
  • Teknologia
  • Tuote-Ihmiset Ja Joukkueet
  • Varastointi
  • Rahoitusprosessit
Web-Käyttöliittymä

Django-, Flask- ja Redis-opetusohjelma: Web-sovellusten istunnon hallinta Python-kehysten välillä

Django vs. pullo: Kun Django on väärä valinta

Rakastan ja käytän Django monissa henkilökohtaisissa ja asiakasprojekteissani, enimmäkseen klassisemmille verkkosovelluksille ja relaatiotietokantoihin liittyville. Django ei kuitenkaan ole hopealuoti.

Suunnittelun mukaan Django on hyvin tiukasti yhdistetty sen ORM-, Template Engine System- ja Settings-objektiin. Lisäksi se ei ole uusi projekti: se kuljettaa paljon matkatavaroita pysyäkseen taaksepäin yhteensopivina.

Jotkut Python-kehittäjät pitävät tätä suurena ongelmana. He sanovat, että Django ei ole tarpeeksi joustava ja välttää sitä mahdollisuuksien mukaan ja käyttää sen sijaan Python-mikrokehystä, kuten Flask.



En ole samaa mieltä. Django on hieno, kun sitä käytetään sopiva paikka ja aika , vaikka se ei sovi joka projektin tekniset tiedot Kuten mantra menee: 'Käytä oikeaa työkalua työhön'.

(Jopa silloin, kun se ei ole oikea paikka ja aika, joskus ohjelmoinnilla Djangon kanssa voi olla ainutlaatuisia etuja.)

Joissakin tapauksissa voi olla mukavaa käyttää kevyempää kehystä (kuten Pullo ). Usein nämä mikrokehykset alkavat loistaa, kun huomaat kuinka helppoa niitä on hakata.

Mikrokehykset pelastukseen

Muutamassa asiakasprojektissani olemme keskustelleet Djangosta luopumisesta ja siirtymisestä mikrokehykseen, tyypillisesti kun asiakkaat haluavat tehdä mielenkiintoisia juttuja (yhdessä tapauksessa esimerkiksi upottaa ZeroMQ sovellusobjektissa) ja projektin tavoitteet näyttävät olevan vaikeampia saavuttaa Djangolla.

Pullosta pidän yleisemmin hyödyllisenä:

  • Yksinkertainen REST-sovellusliittymä
  • Sovellukset, jotka eivät vaadi pääsyä tietokantaan
  • NoSQL-pohjaiset verkkosovellukset
  • Verkkosovellukset, joilla on hyvin erityiset vaatimukset, kuten mukautetut URL-määritykset

Samanaikaisesti sovelluksemme vaati käyttäjien rekisteröintiä ja muita yleisiä tehtäviä, jotka Django ratkaisi vuosia sitten. Pienen painonsa vuoksi pullossa ei ole samaa työkalupakettia.

Esiin nousi kysymys: onko Django kaikki vai ei-sopimus?

Esiin nousi kysymys: onko Django kaikki vai ei-sopimus? Pitäisikö meidän pudottaa se täysin vai voimmeko oppia yhdistämään sen muiden mikrokehysten tai perinteisten kehysten joustavuuteen? Voimmeko valita kappaleet, joita haluamme käyttää, ja välttää muita?

Voimmeko saada molempien maailmojen parhaat puolet? Sanon kyllä, varsinkin istunnonhallinnassa.

(Puhumattakaan, siellä on paljon projekteja Django-freelancereille.)

Nyt Python-opetusohjelma: Django-istuntojen jakaminen

Tämän viestin tarkoituksena on delegoida käyttäjien todentamisen ja rekisteröinnin tehtävät Djangolle, mutta käytä Redistä käyttäjän istuntojen jakamiseen muiden kehysten kanssa. Voin ajatella muutamia tilanteita, joissa jotain tällaista olisi hyödyllistä:

  • Sinun on kehitettävä REST-sovellusliittymä erillään Django-sovelluksestasi, mutta haluat jakaa istuntotiedot.
  • Sinulla on tietty komponentti, joka saatetaan joutua korvaamaan myöhemmin tai laajentamaan jostain syystä ja tarvitset silti istuntotietoja.

Tässä opetusohjelmassa käytän Redis jakaa istuntoja kahden kehyksen välillä (tässä tapauksessa Django ja Flask). Käytän nykyisessä asennuksessa SQLite käyttäjätietojen tallentamiseksi, mutta voit liittää taustasi tarvittaessa NoSQL-tietokantaan (tai SQL-pohjaiseen vaihtoehtoon).

Istuntojen ymmärtäminen

Jos haluat jakaa istuntoja Djangon ja Pullon välillä, meidän on tiedettävä vähän siitä, kuinka Django tallentaa istuntotietonsa. Django dos ovat melko hyviä, mutta annan taustan täydellisyydelle.

Istunnonhallinnan lajikkeet

Yleensä voit hallita Python-sovelluksesi istuntotietoja kahdella tavalla:

  • Evästepohjaiset istunnot : Tässä tilanteessa istuntotietoja ei ole tallennettu tietokantaan. Sen sijaan se sarjoitetaan, allekirjoitetaan (SECRET_KEY-tunnuksella) ja lähetetään asiakkaalle. Kun asiakas lähettää kyseisen tiedon takaisin, sen eheys tarkistetaan väärentämisen varalta ja se poistetaan palvelimelta uudelleen.

  • Tallennuspohjaiset istunnot : Tässä tilanteessa istuntotiedot itse ovat ei lähetetään asiakkaalle. Sen sijaan lähetetään vain pieni osa (avain) nykyisen käyttäjän henkilöllisyyden osoittamiseksi istuntokauppaan.

Esimerkissämme meitä kiinnostaa enemmän jälkimmäinen skenaario: haluamme, että istuntotietomme tallennetaan taustapäähän ja tarkistetaan sitten pullossa. Sama voidaan tehdä entisessä, mutta kuten Djangon asiakirjoissa mainitaan, on joitain huoli turvallisuudesta ensimmäisen menetelmän.

Yleinen työnkulku

Istunnon käsittelyn ja hallinnan yleinen työnkulku on samanlainen kuin tämä kaavio:

Kaavio, joka näyttää käyttäjän istuntojen hallinnan Pullon ja Djangon välillä käyttämällä Redistä.

Käydään läpi istunnon jakaminen tarkemmin:

  1. Kun uusi pyyntö tulee sisään, lähetä se ensin rekisteröidyn kautta väliohjelmisto Django-pinossa. Olemme kiinnostuneita tästä SessionMiddleware luokka, joka, kuten voit odottaa, liittyy istunnon hallintaan ja käsittelyyn:

    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)

    Tässä katkelmassa Django nappaa rekisteröidyt SessionEngine (pääsemme siihen pian), otteet SESSION_COOKIE_NAME alkaen request (sessionid, oletusarvoisesti) ja luo uuden esiintymän valitusta SessionEngine käsittelemään istunnon tallennustilaa.

  • Myöhemmin (kun käyttäjänäkymä on käsitelty, mutta silti väliohjelmistopinossa), istunto moottori kutsuu tallennusmenetelmänsä tallentaakseen muutokset tietovarastoon. (Näkymän käsittelyn aikana käyttäjä on saattanut muuttaa istunnon aikana joitain asioita, esimerkiksi lisäämällä uuden arvon istuntoobjektiin request.session -näppäimellä.) Sitten SESSION_COOKIE_NAME lähetetään asiakkaalle. Tässä on yksinkertaistettu versio:

    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

Olemme erityisen kiinnostuneita SessionEngine luokka, jonka korvataan jollakin tietojen tallentamiseen ja lataamiseen Redisin taustapäähän ja takaisin.

Onneksi on olemassa muutama projekti, jotka jo hoitavat tämän meille. Tässä esimerkki redis_sessions_fork . Kiinnitä huomiota save ja load menetelmät, jotka on kirjoitettu tallentamaan ja lataamaan istunto Redisiin ja sieltä:

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)

On tärkeää ymmärtää, miten tämä luokka toimii, koska meidän on toteutettava jotain vastaavaa pullossa istuntotietojen lataamiseksi. Katsotaanpa tarkemmin REPL-esimerkillä:

>>> 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}

Istuntokaupan käyttöliittymä on melko helppo ymmärtää, mutta konepellin alla tapahtuu paljon. Meidän pitäisi kaivaa hieman syvemmälle, jotta voimme toteuttaa jotain vastaavaa pullossa.

Huomaa: Voit kysyä: 'Miksi ei vain kopioida SessionEngine pulloon?' Helpommin sanottu kuin tehty. Kuten keskustelimme alussa, Django on tiukasti yhdistetty sen Asetukset-objektiin, joten et voi vain tuoda jotakin Django-moduulia ja käyttää sitä ilman ylimääräisiä töitä.

Django-istunnon (de-) sarjallisuus

Kuten sanoin, Django tekee paljon työtä peittääkseen istuntotallennuksensa monimutkaisuuden. Tarkistetaan Redis-avain, joka on tallennettu yllä oleviin katkelmiin:

>>> store.session_key u'ery3j462ezmmgebbpwjajlxjxmvt5adu'

Antaa nyt kysyä kyseisen avaimen redis-cli:

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

Se mitä näemme täällä on hyvin pitkä, Base64-koodattu merkkijono. Ymmärtääksemme sen tarkoituksen, meidän on tarkasteltava Djangon SessionBase luokassa nähdäksesi, miten sitä käsitellään:

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 {}

Koodausmenetelmä sarjoittaa tiedot ensin nykyisellä rekisteröidyllä sarjaliitännällä. Toisin sanoen se muuntaa istunnon merkkijonoksi, jonka se voi myöhemmin muuntaa takaisin istunnoksi (katso lisätietoja SESSION_SERIALIZER-ohjeista). Sitten se hajauttaa sarjoitetut tiedot ja käyttää tätä hajautusta myöhemmin allekirjoituksena istunnon tietojen eheyden tarkistamiseksi. Lopuksi se palauttaa kyseisen tietoparin käyttäjälle Base64-koodatuksi merkkijonoksi.

Muuten: ennen versiota 1.6 Django epäonnistui käyttämään suolakurkkua istuntotietojen sarjoitukseen. Johdosta turvallisuuskysymykset , oletussarjamenetelmä on nyt django.contrib.sessions.serializers.JSONSerializer.

Koodataan esimerkkiistunto

Katsotaanpa istunnonhallintaprosessi toiminnassa. Tässä istuntosanakirjamme on yksinkertaisesti laskenta ja jokin kokonaisluku, mutta voit kuvitella, kuinka tämä yleistyy monimutkaisemmille käyttäjäistunnoille.

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

Store-menetelmän (u’ZmUxOTY… == ’) tulos on koodattu merkkijono, joka sisältää sarjoitetun käyttäjäistunnon ja sen hash. Kun puramme sen, palautamme todellakin sekä hashin (’fe1964e…’) että istunnon ({'count':1}).

Huomaa, että dekoodausmenetelmä varmistaa, että hash on oikea kyseiselle istunnolle, mikä takaa tietojen eheyden, kun käytämme sitä Pullossa. Meidän tapauksessamme emme ole liian huolissamme siitä, että istuntoa muutetaan asiakkaan puolella, koska:

  • Emme käytä evästepohjaisia ​​istuntoja eli emme lähetä kaikki käyttäjätiedot asiakkaalle.

  • Pullossa tarvitsemme vain luku -muodon SessionStore joka kertoo meille, onko annettu avain olemassa vai ei, ja palauttaa tallennetut tiedot.

Laajentaminen pulloon

Seuraavaksi luodaan yksinkertaistettu versio Redis-istunnon moottorista (tietokanta), jotta se toimisi pullon kanssa. Käytämme samaa SessionStore (määritelty edellä) perusluokkana, mutta meidän on poistettava osa sen toiminnoista, esimerkiksi tarkistamalla virheelliset allekirjoitukset tai muokkaamalla istuntoja. Olemme kiinnostuneita vain luku -muodosta SessionStore joka lataa Djangolta tallennetut istuntotiedot. Katsotaanpa, miten se tulee yhteen:

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 {}

Tarvitsemme vain load menetelmä, koska se on vain luku -tallennus. Tämä tarkoittaa, että et voi kirjautua ulos suoraan pullosta. sen sijaan haluat ehkä ohjata tämän tehtävän Djangoon. Muista, että tavoitteena on hallita näiden kahden Python-kehyksen välisiä istuntoja, jotta saat enemmän joustavuutta.

Pulloistunnot

Pullon mikrokehys tukee evästepohjaisia ​​istuntoja, mikä tarkoittaa, että kaikki istunnon tiedot lähetetään asiakkaalle, Base64-koodattu ja kryptografisesti allekirjoitettu. Mutta itse asiassa emme ole kovin kiinnostuneita Flaskin istuntotuesta.

Tarvitsemme on saada Djangon luoma istuntotunnus ja tarkistaa se Redis-taustaa vasten, jotta voimme olla varmoja, että pyyntö kuuluu ennalta allekirjoitetulle käyttäjälle. Yhteenvetona voidaan todeta, että ihanteellinen prosessi olisi (tämä synkronoidaan yllä olevan kaavion kanssa):

  • Nappaa Django-istunnon tunnus käyttäjän evästeestä.
  • Jos istunnon tunnus löytyy Redisistä, palautamme kyseistä tunnusta vastaavan istunnon.
  • Jos ei, ohjaamme ne kirjautumissivulle.

On kätevää, jos sisustaja tarkistaa nämä tiedot ja asettaa nykyisen user_id osaksi g muuttuja pullossa:

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

Yllä olevassa esimerkissä käytämme edelleen SessionStore määritimme aiemmin hakemaan Django-tiedot Redikseltä. Jos istunnossa on _auth_user_id, palautamme sisällön näkymäfunktiosta; muuten käyttäjä ohjataan kirjautumissivulle, aivan kuten halusimme.

Liimataan asioita yhdessä

Evästeiden jakamiseksi minusta on kätevää aloittaa Django ja Flask a WSGI ja liimaa ne yhteen. Tässä esimerkissä olen käyttänyt KirsikkaPy :

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)

Sen avulla Django palvelee '/': ssä ja Flask '/ backend' -päätteissä.

Tiivistettynä

Sen sijaan, että tutkisin Djangoa tai pulloa tai kannustan sinua vain oppimaan Pullon mikrokehyksen, olen hitsannut Djangon ja Pullon yhteen ja saanut heidät jakamaan samat istunnon tiedot todennusta varten delegoimalla tehtävän Djangolle. Kun Djangolla on runsaasti moduuleja käyttäjien rekisteröinnin, kirjautumisen ja uloskirjautumisen ratkaisemiseksi (vain muutamia mainitakseni), näiden kahden kehyksen yhdistäminen säästää arvokasta aikaa ja tarjoaa sinulle mahdollisuuden hakkeroida hallittavissa oleviin mikrokehyksiin, kuten Pullo.

Mielen silmä - katsaus datan visualisointipsykologiaan

Ux-Suunnittelu

Mielen silmä - katsaus datan visualisointipsykologiaan
Tekoälyn nykyisyys ja tulevaisuus suunnittelussa (infografiikan kanssa)

Tekoälyn nykyisyys ja tulevaisuus suunnittelussa (infografiikan kanssa)

Ux-Suunnittelu

Suosittu Viestiä
Urheilukuvaus iPhonella: kuinka voit tallentaa liikkuvia kohteita paremmin
Urheilukuvaus iPhonella: kuinka voit tallentaa liikkuvia kohteita paremmin
Suunnitteluajattelun arvo liiketoiminnassa
Suunnitteluajattelun arvo liiketoiminnassa
Johdanto Nameko-palvelun python-mikropalveluihin
Johdanto Nameko-palvelun python-mikropalveluihin
Toimittaja, ApeeScape Product and Project Management -blogit
Toimittaja, ApeeScape Product and Project Management -blogit
7 ilmaista Instagram-viestimallia virkistämään syötteesi
7 ilmaista Instagram-viestimallia virkistämään syötteesi
 
CSS-asettelun opetusohjelma: klassisista lähestymistavoista uusimpiin tekniikoihin
CSS-asettelun opetusohjelma: klassisista lähestymistavoista uusimpiin tekniikoihin
Tie parempaan ketterään testaukseen
Tie parempaan ketterään testaukseen
Harmaa aine - mikä on miellekartta suunnitteluprosessissa?
Harmaa aine - mikä on miellekartta suunnitteluprosessissa?
Kuinka hallita Design Divaa (eikä olla yksi)
Kuinka hallita Design Divaa (eikä olla yksi)
Kuinka ottaa täydellinen peiliselfie iPhonellasi
Kuinka ottaa täydellinen peiliselfie iPhonellasi
Luokat
KetteräSijoittajat Ja RahoitusTyökalut Ja OppaatTietojenkäsittely Ja TietokannatJaetut JoukkueetVarastointiRahoitusprosessitKetterä KykyiOS-vinkkejäVinkkejä Ja Työkaluja

© 2023 | Kaikki Oikeudet Pidätetään

socialgekon.com