Sessiot, evästeet, autentikointi ja tiedostot - Demo 4
- Laskuri sessioilla
- Laskuri evästeillä
- Tiedostojen käsittely
- Tiedoston lataus palvelimelle
- Autentikointi
- MD5
Harjoitellaan sessioiden käyttöä WWW-sovelluksen tekemisessä. Toteutaan ensin sessioilla yksinkertainen lomake, joka laskee lukuja yhteen. Yritetään sen jälkeen toteuttaa vastaava lomake evästeiden avulla. Lisäksi toteutetaan lomake, jolla voi kirjoittaa rivin tekstitiedostoon tai tyhjentää tekstitiedoston. Lopuksi toteutetaan yksinkertainen lomake, jolla voi ladata tiedoston palvelimelle.
Laskuri sessioilla

Käytä apuna dokumenttia: mod_pythonin Session-luokka
- mod_pythonissa kannattaa sessioiden
aktivointi tehdä omalla erillisellä käsittelijällä seuraavasti:
- Kirjoita .htaccess-tiedostoon seuraavat rivit:
PythonDebug On AddHandler mod_python .py PythonHandler sessions PythonHandler mod_python.publisher
- Apache kutsuu määriteltyjä käsittelijöitä järjestyksessä. Kirjoita
sessions.py-tiedostoon seuraavanlainen käsittelijä:
from mod_python import apache, Session def handler(req): if not hasattr(req, 'session'): req.session = Session.Session(req) return apache.OKKäsittelijä luo uuden istunnon (session) jos sellaista ei jo ole olemassa ja tallentaa istunnon req-objektiin. Jonossa seuraavana oleva käsittelijä kuljettaa valmiin session req-objektin mukana.
- Kirjoita .htaccess-tiedostoon seuraavat rivit:
- Luo kuvan mukainen XHTML-sivu käyttäen mod_pythonin publisheria. Kirjoita siis
.py-päätteinen tiedosto jossa on vähintään yksi funktio esim.
def index(req): return "Tähän koko sivun sisältö"
- Tee body-osaan lomake, jonka action-attribuutissa on req.uri-muuttujan arvo eli mod_python-sovelluksesi osoite.
- Lisää lomakkeelle tekstilaatikko, jonka otsikkona (label) on "Anna luku" ja name-ominaisuudessa luku.
- Lisää lomakkeelle lisäksi submit-painike.
- Summan tuloksen säilyttämiseksi tarvitaan sessiomuuttujaa, joka säilyttää
arvonsa koko istunnon ajan. Sessiomuuttujaa voi käyttää seuraavalla tavalla:
try: req.session['summa'] += 1 except: req.session['summa'] = 0 req.session.save()Sessiomuuttujat toimivat tavallisen dict-taulukon tapaan.
Ensimmäisellä käyttökerralla muuttujalla ei ole arvoa joten varminta on testata pythonin poikkeuskäsittelyn (try...except) avulla onko sessiomuuttujalla jo arvo vai ei. Jos muuttuja on alustamaton niin yritys lisätä muuttujan arvoa aiheuttaa poikkeuksen jolloin voidaan tehdä muuttujan alustaminen.
Sessiomuuttujien sisältö ei jää automaattisesti talteen vaan aina täytyy muistaa sessiomuuttujien manipuloinnin jälkeen tallentaa sessio komennolla req.session.save()!
- Ota lomakkeelle annettu luku talteen. Tarkista, että lomakkeelle on varmasti syötetty kokonaisluku. Lisää luku haluamaasi sessiomuuttujaan. Tulosta yhteenlaskettu summa sivulle.
-
Istunnon ja siihen liittyvien muuttujien ylläpitäminen edellyttää, että
käytetty selain tukee evästeitä. Evästeessä kuljetetaan selaimen ja WWW-palvelimen
välillä istuntoon liittyvää tunnistetta. Kokeile Web Developer Toolbarin
avulla millaisen evästeen mod_python asettaa käyttäessäsi sessioita.
Seuraavassa kuvassa hahmotetaan sessioon liittyvää toimintaa PHP-sovelluksessa. Toiminta on täysin vastaavaa mod_python-sovelluksilla.

Testauksessa kannattaa käyttää myös Web Developer Toolbarista löytyvää valintaa Cookies | Clear Session Cookies. Näin pääset laskurin alkutilaan.
- Tee uusi sivu joka poistaa istuntosi session.invalidate()-metodilla. Kokeile nollautuuko laskuri.
Laskuri evästeillä
Edellisen esimerkin laskurin voisi periaatteessa tehdä evästeillä. Tällöin summaa olisi mahdollista tallentaa myös selaimen sulkemisen ajaksi. Muuta edellisen esimerkin laskuri toimimaan evästeillä sessioiden sijaan.
- Evästeen asettaminen:
from mod_python import apache, Cookie keksi = Cookie.Cookie('nimi','arvo', expires=time.time()+24*60*60, path="/~tjlahton/", domain=".jyu.fi") Cookie.add_cookie(req, keksi)- Eväste on asetettava ennen varsinaista dokumenttia, koska se tulee HTTP-otsikkotietoihin.
- Evästeen kestoksi tulee siis yksi päivä.
- Evästeen arvon käyttäminen:
keksit = Cookie.get_cookies(req) arvo = keksit["nimi"].value
- Testaa laskurin toimintaa. Kokeile myös sulkea välillä selain ja palata sitten samalle sivulle.
- Toiminnasta huomaa sen virheen, että summa päivittyy oikeaksi aina vasta seuraavalla sivun latauksella. Tämä johtuu siitä, että evästeen arvo on käytettävissä aina vasta seuraavalla sivun latauskerralla. Sessioissa taas arvoa voidaan käyttää heti sen asettamisen jälkeen.
- Evästeet voi poistaa Web Developer Toolbarin toiminnolla Cookies | Delete Path Cookies.
- Muuta toiminta siten, että tuloksena näytetään evästeen arvon ja lomakkeelta lähetetyn arvon summa.

Tiedostojen käsittely

Katso mallia Pythonin dokumentaatiosta: Reading and Writing Files.
Tehdään lomake, jolla voi kirjoittaa rivin tiedostoon tai tyhjentää tiedoston.
- Luo uusi mod_python ohjelma
- Luo sivulle mallikuvan näköinen lomake. Lomakkeella on siis tarkoitus valita valintanapin (radio) avulla lisätäänkö tiedostoon tekstiä vai tyhjennetäänkö tiedosto. Lisäksi lomakkeella on tekstikenttä tekstiä varten ja submit-painike.
- Tutki tiedoston alussa, onko submit-painiketta painettu. Jos painiketta on painettu,
kirjoitetaan tiedostoon lisää tekstiä tai tyhjennetään tiedosto:
- Tutki valintanapin arvosta, halusiko käyttäjä tyhjentää tiedoston vai lisätä sinne rivin.
- Jos käyttäjä halusi tyhjentää tiedoston, avaa tiedosto (esimerkiksi "testi.txt")
kirjoitustilaan siten, että kirjoitus alkaa tiedoston alusta ja vanha sisältö tuhotaan. Kirjoita sen
jälkeen tiedostoon tyhjä merkkijono.
f = open(os.path.join(os.path.dirname(req.filename), 'testi.txt'), 'w') f.write("") f.close() - Jos käyttäjä taas halusi lisätä rivin tiedoston, avaa tiedosto (esimerkiksi "testi.txt") kirjoitustilaan siten, että kirjoitus alkaa tiedoston lopusta ja vanha sisältö säilytetään. Kirjoita sen jälkeen tiedostoon käyttäjän tekstikentässä syöttämä arvo (tutki ensin oliko arvo joku muu kuin tyhjä, jottet kirjoita turhaan). Kirjoita rivin perään myös rivinvaihto.
- Muista lopuksi sulkea tiedosto.
- Muista asettaa tiedostoille ja kansioille riittävät kirjoitusoikeudet.
- Tulostetaan vielä sivun loppuun tiedoston rivit pre-elementin sisälle:
- Tutki ensin onko tiedostoa olemassa
import os.path os.path.isfile(tiedosto)
- Jos tiedosto löytyy, niin lue sen kaikki rivit johonkin taulukkomuuttujaan.
- Tulosta sen jälkeen kaikki rivit pre-elementin sisälle. Varmista, että mahdolliset <, > ja &-merkit ovat oikein koodattuina (cgi.escape).
- Tutki ensin onko tiedostoa olemassa
- Testaa lomakkeen toimintaa. Kokeile kirjoittaa myös XHTML-koodia, niin näet toimiiko merkkien koodaus.
Tiedoston lataus palvelimelle

Tehdään yksinkertainen lomake, jolla voi ladata tiedoston palvelimelle.
- Luo uusi mod_python-ohjelma
- Tee samaan hakemistoon myös kansio tiedostot ja laita sille kirjoitusoikeudet päälle kaikille.
- Tee sivulle lomake, jolla voi ladata tiedoston palvelimelle:
- Muista laittaa form-elementille määritys enctype="multipart/form-data.
- Tutki tiedoston alussa, onko submit-painiketta painettu. Jos painiketta on painettu,
lisätään palvelimelle tiedosto:
- Testaa ensin, onko käyttäjä valinnut tiedoston:
if form.has_key('file') and form['file'].filename: - Jos tiedostonsiirto vaikuttaisi onnistuvan, siirrä tiedosto kansioon tiedostot seuraavan mallin mukaisesti. Selvitä
mitä funktiot os.path.basename, os.path.join ja os.path.dirname tekevät:
def fbuffer(f, chunk_size=10000): while True: chunk = f.read(chunk_size) if not chunk: break yield chunk tiedosto = form['file'] # polku upload-kansioon polku = os.path.join(os.path.dirname(req.filename), 'upload') # polku tallennettavaan tiedostoon upload = os.path.join(polku, "tiedostonnimi.txt") f = open(upload, 'wb', 10000) for chunk in fbuffer(tiedosto.file): f.write(chunk) f.close()
- Testaa ensin, onko käyttäjä valinnut tiedoston:
- Tulosta käyttäjälle lomakkeen alkuun tieto tiedonsiirron onnistumisesta tai epäonnistumisesta. Jos tiedostoon kirjoittaminen epäonnistuu palauttaa Python poikkeuksen, jonka voit napata kiinni.
- Testaa lomakkeen toimintaa.
- Lisäksi olisi järkevää tarkistaa ainakin tiedostopääte, jottei palvelimelle voi ladata vaikkapa vahinkoa tekeviä skriptejä. Pohdittavaksi jää myös minne saatu data kannattaa tallentaa ja millaisilla oikeuksilla tiedostoihin (tai tietokantatietueisiin) pääsee käsiksi.
Autentikointi
Käyttäjän kirjautuminen ja autentikointi järjestelmään tehdään seuraavalla tavalla:
- Lisää .htaccess-tiedostoon yksi käsittelijä sessiokäsittelijän ja varsinaisen käsittelijän väliin. esim:
PythonHandler autentikointi
- Luo autentikointi.py johon kirjoitat käsittelijän:
from mod_python import apache, Session from mod_python import util def handler(req): try: if req.session["kirjautunut"] == "ok": return apache.OK except: form = util.FieldStorage(req) tunnus = form.getfirst("tunnus") salasana = form.getfirst("salasana") if tunnus == "ope" and salasana == "ope": req.session["kirjautunut"] = "ok" return apache.OK req.content_type = "text/html" req.write( "Et ole kirjautunut. Tähän tulisi kirjautumiseen vaadittava lomake" ) return apache.DONE- Käsittelijä tarkistaa löytyykö sessiomuuttujasta "kirjautunut" tieto siitä, että kirjautuminen on tehty. Jos löytyy niin palautetaan ok ja apache jatkaa käsittelyä seuraavalla käsittelijällä
- Jos kirjautumista ei ole tehty niin kokeillaan onko lomakkeelta tullut kirjautumiseen tarvittavat tiedot ja ovatko ne oikein. Jos ovat niin jatketaan normaalisti.
- Jos kirjautuminenkaan ei onnistu niin tulostetaan kirjautumiseen vaadittava lomake ja palautetaan apache.DONE, joka estää loppujen käsittelijöiden suorittamisen ja näkyville jää siis vain kirjautumislomake.
- Kirjoita kirjautumiseen vaadittava lomake ja kokeile kuinka kirjautuminen onnistuu
- Kirjoita uusi sivu jolla voi uloskirjautua eli sivu poistaa istunnon (session) tai asettaa uudelleen kirjautumisessa käytetytn sessiomuuttujan.
MD5
- Lisää kirjautumiseen tunnusten ja salasanojen lukeminen tiedostosta. Keksi itse tunnussalasanatiedostollesi hyvä formaatti.
- Salasanoja ei pidä koskaan tallentaa selkokielisinä vaan aina MD5- tai jollakin vastaavalla tavalla koodattuina
- MD5-koodausta voit pythonissa kokeilla seuraavalla tavallla:
import md5 tunnus = "ope" salasana = "password" koodattu_salasana = md5.new(salasana).hexdigest() #hieman turvallisempi versio salt = "!f00F" koodattu_salasana = md5.new(salasana + salt).hexdigest()
Salasanan oikeellisuutta testattaessa verrataan siis annetun salasanan ja tallennetun salasanan MD5-koodattuja muotoja.
- Koodaa salasanatiedostosi salasanat MD5-koodauksella.

Käyttäjien kommentit