Final grammar and style fixes

This commit is contained in:
Marko Korhonen 2020-05-20 16:27:39 +03:00
parent 1ba0395634
commit 77ae3afe1b
No known key found for this signature in database
GPG key ID: 911B85FBC6003FE5
9 changed files with 36 additions and 37 deletions

View file

@ -1,5 +1,5 @@
\chapter{Projekti}
Tein insinöörityön yhteydessä full-stack projektin, jossa sekä palvelin- että asiakaspuolen ohjelmointi tehtiin Rustilla.
Tein insinöörityön yhteydessä full-stack-projektin, jossa sekä palvelin- että asiakaspuolen ohjelmointi tehtiin Rustilla.
\section{Tavoitteet}
Tavoitteena ei ollut saada aikaiseksi mitään todella monimutkaista ohjelmaa, vaan puhtaasti arvioida Rustin soveltuvuutta web-ohjelmointiin yksinkertaisella esimerkkiprojektilla.
@ -11,20 +11,20 @@ Tavoitteena ei ollut saada aikaiseksi mitään todella monimutkaista ohjelmaa, v
\label{fig:architecture}
\end{figure}
Kuvassa \ref{fig:architecture} näkee sovelluksen arkkitehtuurin. Sovelluksen asiakaspuoli koostuu mallin keltaisista laatikoista ja palvelinpuoli sininisistä. Nuolet merkitsevät datan liikkumista, mikä on kaikkialla kaksisuuntaista. Yew ja Actix ovat valitsemani asiakas- ja palvelinpuolen sovelluskehykset.
Kuvassa \ref{fig:architecture} näkee sovelluksen arkkitehtuurin. Sovelluksen asiakaspuoli koostuu mallin keltaisista laatikoista ja palvelinpuoli sinisistä. Nuolet merkitsevät datan liikkumista, mikä on kaikkialla kaksisuuntaista. Yew ja Actix ovat valitsemani asiakas- ja palvelinpuolen sovelluskehykset.
\section{Kehitysympäristön asennus}
Rust-projektin aloittamiseksi kehittäjä tarvitsee koneelleen Rustin paketinhallintatyökalun, Cargon (katso luku \ref{sect:paketinhallinta}). Olen itse Linux-käyttäjä, joten sain asennettua Cargon Linux-jakeluni ohjelmavarastosta. Mac- ja Windows-käyttäjille suosittelen Rustup-asennusohjelman käyttämistä. Lisää tietoa Rustin asentamisesta saa Rustin kotisivuilta \cite{rust:install}.
Projektin saa initialisoitua komennolla \mintinline{shell}{cargo init projektinnimi}. Tämä komento luo hakemiston ''projektinnimi'', minkä sisällä on Cargon konfiguraatiotiedosto Cargo.toml, jossa voi määrittää projektin tiedot ja riippuvuudet.
Lähdekoodi sijaitsee hakemistossa ''src''. Cargo kirjoittaa hakemistoon valmiiksi ''main.rs'' -tiedoston, jossa on ''Hello world!'' esimerkkikoodi. ''main.rs'' on aina Rust-ohjelman ensimmäiseksi suoritettava tiedosto, eli niin kutsuttu entrypoint. ''main.rs''-tiedoston sisällä pitää olla ''main()''-funktio, josta ohjelman suoritus alkaa. Projektin voi suorittaa komennolla \mintinline{shell}{cargo run}.
Lähdekoodi sijaitsee hakemistossa ''src''. Cargo kirjoittaa hakemistoon valmiiksi ''main.rs'' -tiedoston, jossa on ''Hello world!'' -esimerkkikoodi. ''main.rs'' on aina Rust-ohjelman ensimmäiseksi suoritettava tiedosto, eli niin kutsuttu entrypoint. ''main.rs''-tiedoston sisällä pitää olla ''main()''-funktio, josta ohjelman suoritus alkaa. Projektin voi suorittaa komennolla \mintinline{shell}{cargo run}.
\clearpage
Suosittelen asentamaan myös muutaman Cargon liitännäisen helpottamaan kehitystä. cargo-watchin avulla voi ajaa komennon aina, kun lähdekoodi muuttuu. Esimerkiksi komennolla \mintinline{shell}{cargo watch -x run} voi kääntää ja käynnistää projektin aina uudelleen, kun lähdekoodi muuttuu. cargo-add -liitännäisellä voi helposti lisätä uusia riippuvuuksia projektiinsa. Esimerkiksi Actix webin saa lisättyä komennolla \mintinline{shell}{cargo add actix-web}.
Suosittelen asentamaan myös muutaman Cargon liitännäisen helpottamaan kehitystä. cargo-watchin avulla voi ajaa komennon aina, kun lähdekoodi muuttuu. Esimerkiksi komennolla \mintinline{shell}{cargo watch -x run} voi kääntää ja käynnistää projektin aina uudelleen, kun lähdekoodi muuttuu. cargo-add-liitännäisellä voi helposti lisätä uusia riippuvuuksia projektiinsa. Esimerkiksi Actix webin saa lisättyä komennolla \mintinline{shell}{cargo add actix-web}.
Näillä ohjeilla pääsee alkuun palvelinpuolen kehityksessä. Asiakaspuolen kehityksen käynnistäminen vaati vielä muutaman lisävaiheen, siitä lisää luvussa \ref{sect:asiakaspuoli:asennus}.
Näillä ohjeilla pääsee alkuun palvelinpuolen kehityksessä. Asiakaspuolen kehityksen käynnistäminen vaati vielä muutaman lisävaiheen. Siitä lisää luvussa \ref{sect:asiakaspuoli:asennus}.
\section{Palvelinpuoli}
\subsection{Kehys}
@ -63,7 +63,7 @@ Todentamiseen päätin käyttää JSON Web Tokeneita. Ne ovat standardoitu (RFC
\begin{figure}[h]
\centering
\includegraphics[width=\linewidth]{illustration/jwt.png}
\caption{JWT:n osat havainnollistettuna käyttämällä jwt.io -sivustoa \cite{jwt:home}}
\caption{JWT:n osat havainnollistettuna käyttämällä jwt.io-sivustoa \cite{jwt:home}}
\label{fig:jwt}
\end{figure}
@ -79,7 +79,7 @@ Ylätunniste koostuu JSON-objektista [koodiesimerkki \ref{code:json:jwt-header}]
\bigskip
Tokenin toisessa osassa, hyötykuormassa, on itse tokenin sisältö [koodiesimerkki \ref{code:json:jwt}]. Tokenin sisällön voi päättää kokonaan itse, vaikkakin joitakin standardeja kenttiä on määritetty. Esimerkiksi iss (issuer), sub (subject) ja exp (expiration time). Päätin sisällyttää myös tiedon siitä, että onko käyttäjä ylläpitäjä, koska tätä tietoa voi sitten käyttää asiakaspuolella esimerkiksi käyttöliittymän muokkaamiseen käyttäjän roolin perusteella. Usein myös käyttäjän nimi sisällytetään tokeniin. Tokenin sisältöä suunnitellessa kannattaa pitää mielessä, että sen sisältö on nähtävissä kaikille, joten se ei ole oikea paikka tallettaa salaista tietoa, kuten vaikka käyttäjän salasana.
Tokenin toisessa osassa, hyötykuormassa, on itse tokenin sisältö [koodiesimerkki \ref{code:json:jwt}]. Tokenin sisällön voi päättää kokonaan itse, vaikkakin joitakin standardeja kenttiä on määritetty. Esimerkiksi iss (issuer), sub (subject) ja exp (expiration time). Päätin sisällyttää myös tiedon siitä, onko käyttäjä ylläpitäjä, koska tätä tietoa voi sitten käyttää asiakaspuolella esimerkiksi käyttöliittymän muokkaamiseen käyttäjän roolin perusteella. Usein myös käyttäjän nimi sisällytetään tokeniin. Tokenin sisältöä suunnitellessa kannattaa pitää mielessä, että sen sisältö on nähtävissä kaikille, joten se ei ole oikea paikka tallettaa salaista tietoa, kuten vaikka käyttäjän salasana.
\bigskip
@ -94,7 +94,7 @@ Tokenin toisessa osassa, hyötykuormassa, on itse tokenin sisältö [koodiesimer
Tokenin kolmesta osasta viimeinen on allekirjoitus. Se on koostettu ylätunnisteessa [koodiesimerkki \ref{code:json:jwt-header}] määritellyllä algoritmilla käyttämällä parametreina tokenin hyötykuormaa [koodiesimerkki \ref{code:json:jwt}] ja vain palvelimen tiedossa olevaa salasanaa. Koko tokenin turvallisuus perustuu juuri tähän allekirjoitukseen. Sen avulla palvelin voi varmistua siitä, että tokenia ei ole muokannut kukaan, kenellä ei ole tätä salasanaa.
Tokenia varmennettaessa hyötykuorma allekirjoitetaan uudelleen ja tätä uutta allekirjoitusta verrataan tokenin mukana tulleeseen allekirjoitukseen. Jos ne ovat samat, palvelin voi olla varma siitä että tokenin sisältöön voi luottaa. Tämän edellytyksenä tietysti on, että salasanaa on säilytetty turvallisella tavalla.
Tokenia varmennettaessa hyötykuorma allekirjoitetaan uudelleen ja tätä uutta allekirjoitusta verrataan tokenin mukana tulleeseen allekirjoitukseen. Jos ne ovat samat, palvelin voi olla varma siitä, että tokenin sisältöön voi luottaa. Tämän edellytyksenä tietysti on, että salasanaa on säilytetty turvallisella tavalla.
Otetaan esimerkkinä tämän sovelluksen käyttäjä Pasi. Pasi ei ole ylläpitäjä, mutta hän koittaa tehdä itsestään ylläpitäjän muuttamalla omasta tokenistaan parametrin \mintinline{JavaScript}{"admin": false} arvoksi \mintinline{JavaScript}{true}. Kun Pasi lähettää tämän muokatun tokenin palvelimelle, se viedään JWT-validointifunktioon. Palvelin huomaa, että token ei ole enää validi, koska sen sisältöä ei ole allekirjoitettu palvelimen salasanalla.
@ -104,7 +104,7 @@ Projektin JWT-toteutus on liitteessä \ref{appx:jwt}.
\subsection{CORS}
Lisäsin palvelimelle myös Cross-Origin Resource Sharing (CORS) \cite{wiki:cors} -toiminnallisuuden. Oletuksena selaimen lataama ohjelma saa ladata resursseja vain samasta osoitteesta, kuin mistä itse ohjelma on ladattu. Tämä on turvallisuuskäytäntö, joka kulkee nimellä Same-origin policy (SOP) \cite{wiki:sop}. Näihin resursseihin sisältyvät muunmuassa CSS-tyylimääritykset, kuvat ja JavaScript-ohjelmat.
Lisäsin palvelimelle myös Cross-Origin Resource Sharing (CORS) \cite{wiki:cors} -toiminnallisuuden. Oletuksena selaimen lataama ohjelma saa ladata resursseja vain samasta osoitteesta, kuin mistä itse ohjelma on ladattu. Tämä on turvallisuuskäytäntö, joka kulkee nimellä Same-origin policy (SOP) \cite{wiki:sop}. Näihin resursseihin sisältyvät muun muassa CSS-tyylimääritykset, kuvat ja JavaScript-ohjelmat.
\begin{figure}[h]
\centering
@ -132,6 +132,8 @@ CORS:n lisääminen tähän projektiin hoitui Actixin liitännäisellä actix\ch
\subsection{Tietokanta}
\label{project:database}
Tietokannaksi valikoitui itselleni tuttu MySQL. Koska projekti on yksinkertainen todennusdemo, tietokantaan tuli vain yksi taulu. Users-taulu sisältää käyttäjän tiedot: käyttäjänimen, salatun salasanan, tiedon käyttäjän ylläpitäjyydestä sekä käyttäjän luomisajankohta. Tietokannan ER-mallin näkee kuvasta \ref{fig:er-model}.
\begin{figure}[h]
\centering
\includegraphics[width=12cm]{illustration/er-model.pdf}
@ -139,15 +141,13 @@ CORS:n lisääminen tähän projektiin hoitui Actixin liitännäisellä actix\ch
\label{fig:er-model}
\end{figure}
Tietokannaksi valikoitui itselleni tuttu MySQL. Koska projekti on yksinkertainen todennusdemo, tietokantaan tuli vain yksi taulu. Users-taulussa on käyttäjän tiedot: käyttäjänimi, salattu salasana, tieto käyttäjän ylläpitäjyydestä sekä käyttäjän luomisajankohta. Tietokannan ER-mallin näkee kuvasta \ref{fig:er-model}.
Relaatiotietokannan sai helposti yhdistettyä Rust-koodiini Diesel ORM-kirjastolla. Diesel on tähän mennessä käyttämistäni ORM-kirjastoista selkeästi mukavin käyttää.
Käytännöllisimmät ominaisuudet kehittäjän näkökulmasta olivat Dieselin mukana tuleva komentorivikäyttöliittymä ja migraatiot. Jokaiselle taululle luodaan uusi migraatio, esimerkiksi \mintinline{shell}{diesel migration generate users}, jonka jälkeen Dieselin luomaan hakemistoon kirjoitetaan up.sql- ja down.sql-tiedostot [liite \ref{appx:diesel}], eli ohjeet siitä, miten tämä taulu luodaan ja poistetaan. Taulu viedään tietokantaan komennolla \mintinline{shell}{diesel migration run} ja taulun voi poistaa ja luoda uudelleen komennolla \mintinline{shell}{diesel migration redo}. Tämä mahdollistaa myös samalla sen, että versiohallintaan voi tallentaa useita versioita samasta taulusta ja palata helposti takaisin vanhempaan versioon, jos uudemman kanssa ilmenee ongelmia.
\clearpage
Edellä mainitut työkalut helpottivat tietokannan kehitystä huomattavasti. Usein varsinkin projektin alkuvaiheilla tietokanta muuttuu jatkuvasti ja usein tulee tarve poistaa ja luoda tietokanta uudelleen. Monet kehittäjät pitävät juurikin tällaista Dieselin up.sql kaltaista tiedostoa versiohallinnassa ja tarpeen mukaan poistavat tietokannan käsin ja liittävät komennon tiedostosta tietokannan komentorivikäyttöliittymään. Dieseliä käytettäessä tämä tulee tehtyä automaattisesti ja se tuntuu todella luontevalta.
Edellä mainitut työkalut helpottivat tietokannan kehitystä huomattavasti. Usein varsinkin projektin alkuvaiheilla tietokanta muuttuu jatkuvasti ja usein tulee tarve poistaa ja luoda tietokanta uudelleen. Monet kehittäjät pitävät juurikin tällaista Dieselin up.sql:n kaltaista tiedostoa versiohallinnassa ja tarpeen mukaan poistavat tietokannan käsin ja liittävät komennon tiedostosta tietokannan komentorivikäyttöliittymään. Dieseliä käytettäessä tämä tulee tehtyä automaattisesti ja se tuntuu todella luontevalta.
Päätin myös käyttää Dieselin kanssa yhteyksien yhdistämistä (eng. connection pooling). Tämä tarkoittaa sitä, että palvelin luo käynnistyessään prosessin, joka ottaa yhteyden tietokantaan. Tämä prosessi puolestaan jakaa tätä yhteyttä sitä tarvitseville ohjelman osille. Tämä on tehokkaampaa kuin vaihtoehto, jossa otetaan uusi yhteys jokaista tietokantakyselyä varten.
@ -161,14 +161,14 @@ Valitsemani sovelluskehys tukee molempia kirjastoja, mutta päädyin kuitenkin v
WebAssembly-koodin suorittamiseksi selain tarvitsee pienen pätkän JavaScriptiä, joka tekee tarvittavat toimet WebAssembly-ohjelman käynnistämiseksi. Tämän koodin generoi puolestani cargo-web. Lisäksi JavaScriptin suorittamiseen tarvitaan yksi HTML-tiedosto. Tähän tiedostoon voi myös sisällyttää metadataa, kuten esimerkiksi sivuston otsikon, joka näkyy selaimen välilehdessä. Tähän tiedostoon linkitetään myös kaikki muu staattinen data, kuten tyylimääritykset. Nämä tiedostot laitoin käytännön mukaisesti static-nimiseen hakemistoon asiakaspuolen projektin juureen. Tämän hakemiston linkitin symbolisella linkillä palvelinpuolen projektiin, jonka HTTP-serveri voi sitten lähettää HTML-dokumentin, JavaScript-tiedoston ja WebAssembly-binäärin käyttäjän selaimelle.
\subsection{Kehys}
Asiakaspuolen sovelluskehykseksi valitsin Yew:n\cite{yew:home}. Yew muistuttaa hyvin paljon JavaScript-maailmassa suosittua Reactia, eli sen on komponenttipohjainen. Tämä tarkoittaa sitä, että kaikkien ohjelman osien, joilla halutaan näyttää jotakin käyttöliittymän osaa, täytyy implementoida Yew:n Component-rajapintaa. Tässä rajapinnassa on funktiot create, change, update ja view. Näiden funktioiden avulla Yew pystyy orkestroimaan kullakin hetkellä näytettävien komponenttien tilaa.
Asiakaspuolen sovelluskehykseksi valitsin Yew'n\cite{yew:home}. Yew muistuttaa hyvin paljon JavaScript-maailmassa suosittua Reactia, eli sen on komponenttipohjainen. Tämä tarkoittaa sitä, että kaikkien ohjelman osien, joilla halutaan näyttää jotakin käyttöliittymän osaa, täytyy implementoida Yew'n Component-rajapintaa. Tässä rajapinnassa on funktiot create, change, update ja view. Näiden funktioiden avulla Yew pystyy orkestroimaan kullakin hetkellä näytettävien komponenttien tilaa.
Tässä projektissa komponentteja oli kolme: ohjelman juuri [liite \ref{appx:frontend-main}], kirjautumiskomponentti [liite \ref{appx:login}] ja suojatun datan noutamiseen tehty komponenti [liite \ref{appx:protected}].
\subsection{Ulkonäkö}
\label{sect:ulkonäkö}
Olen JavaScript-maailmassa tottunut siihen, että käyttöliittymäkehyksiin löytyy usein kirjasto, joka tarjoaa valmiit tyylimääritykset, mutta en löytänyt vastaavaista kirjastoa, joka toimisi Yew:n kanssa. Kaikki käyttöliittymän elementit olivat siis selaimen oletustyylisiä. En halunnut ryhtyä tässä projektissa kirjoittamaan CSS-määrityksiä alusta alkaen, joten päädyin käyttämään UIkittiä\cite{uikit}. UIkit on CSS-kirjasto, missä on paljon valmiita ja hyvännäköisiä tyylimäärityksiä. UIkitin dokumentaatio on laaja ja siellä on paljon esimerkkejä, joten alkuun pääsi todella nopeasti [kuva \ref{fig:login}].
Olen JavaScript-maailmassa tottunut siihen, että käyttöliittymäkehyksiin löytyy usein kirjasto, joka tarjoaa valmiit tyylimääritykset, mutta en löytänyt vastaavaista kirjastoa, joka toimisi Yew'n kanssa. Kaikki käyttöliittymän elementit olivat siis selaimen oletustyylisiä. En halunnut ryhtyä tässä projektissa kirjoittamaan CSS-määrityksiä alusta alkaen, joten päädyin käyttämään UIkittiä\cite{uikit}. UIkit on CSS-kirjasto, missä on paljon valmiita ja hyvännäköisiä tyylimäärityksiä. UIkitin dokumentaatio on laaja ja siellä on paljon esimerkkejä, joten alkuun pääsi todella nopeasti [kuva \ref{fig:login}].
\begin{figure}[h]
\centering
@ -177,16 +177,16 @@ Olen JavaScript-maailmassa tottunut siihen, että käyttöliittymäkehyksiin lö
\label{fig:login}
\end{figure}
Login-komponentti löytyy kokonaisuudessaan liitteestä \ref{appx:login}. Liitteestä näkee esimerkin Yew:n komponenttirajapinnan käytöstä ja palvelimeen yhdistämisestä. Lisäksi siellä on käytetty UIKit-tyylityksiä.
Login-komponentti löytyy kokonaisuudessaan liitteestä \ref{appx:login}. Liitteestä näkee esimerkin Yew'n komponenttirajapinnan käytöstä ja palvelimeen yhdistämisestä. Lisäksi siellä on käytetty UIKit-tyylityksiä.
\subsection{Reititys}
Reititykseen käytin Yew:n liitännäistä, yew\char`_routeria. Reititys asiakaspuolen ohjelmassa tarkoittaa sitä, että selaimen osoitepalkissa olevan polun mukaan käyttäjä reititetään oikeaan ohjelman osaan. Tämä liittyy käsitykseen yhden sivun ohjelmista (katso luku \ref{sect:spa}), joissa selain suorittaa yhden ohjelman, jonka jälkeen perinteisiä sivujen latauksia ei enää tapahdu. Ohjelma muokkaa osoitepalkissa näkyvää osoitetta, jonka pohjalta sitten reititys oikeaan komponenttiin tapahtuu. Käyttöliittymää muokataan käyttämällä DOM:ia, joka mahdollistaa sivun sisällön muokkaamisen ilman sivun uudelleen lataamista.
Reititykseen käytin Yew'n liitännäistä, yew\char`_routeria. Reititys asiakaspuolen ohjelmassa tarkoittaa sitä, että selaimen osoitepalkissa olevan polun mukaan käyttäjä reititetään oikeaan ohjelman osaan. Tämä liittyy käsitykseen yhden sivun ohjelmista (katso luku \ref{sect:spa}), joissa selain suorittaa yhden ohjelman, jonka jälkeen perinteisiä sivujen latauksia ei enää tapahdu. Ohjelma muokkaa osoitepalkissa näkyvää osoitetta, jonka pohjalta sitten reititys oikeaan komponenttiin tapahtuu. Käyttöliittymää muokataan käyttämällä DOM:ia, joka mahdollistaa sivun sisällön muokkaamisen ilman sivun uudelleenlataamista.
Asiakaspuolen reititys vaatii palvelinpuolelta sen, että kaikki mahdolliset asiakaspuolen reitit palauttavat ohjelman. Toinen edellytys on se, että palvelin ei palauta uudelleenohjausta (HTTP 302), koska silloin myös osoitepalkissa oleva osoite muuttuu, eikä sitä silloin voida välittää asiakaspuolen ohjelmalle.
Yritin pitkään toteuttaa tällaista logiikkaa palvelinpuolelle siinä onnistumatta, mutta onnekseni yew\char`_routerin esimerkeistä löytyi esimerkkikoodia tämän saavuttamiseksi käyttämäni palvelinkehyksen kanssa. Päädyin laittamaan kaikki palvelimen omat reitit polun \mintinline{shell}{/api/} alle, ja asiakaspuolen ohjelman juureen (\mintinline{shell}{/}). Sitten määritin ns. ''catch-all'' reitin, joka palauttaa asiakaspuolen ohjelman ilman uudelleenohjausta. Tämä on Actixissa nimeltään \mintinline{shell}{default_service}.
Myös yew\char`_routerin kanssa oli omat haasteensa. Alkuun en saanut sitä toimimaan ollenkaan, reititin ohjasi kaikki osoitteet ensimmäisenä määritettyyn reittiin, mikä oli tässä tapauksessa ''/''. Ongelman syyksi paljastui yew\char`_routerin Switch-komponentin kokoava ''to'-makro (katso luku \ref{chap:macros}). Ratkaisuna oli reitin ''/'' makron siirtäminen viimeiseksi listassa. Tarkempaa tietoa tästä ongelmasta voi lukea Yew:n dokumentaatiosta \cite{yew:router-problem}.
Myös yew\char`_routerin kanssa oli omat haasteensa. Alkuun en saanut sitä toimimaan ollenkaan, reititin ohjasi kaikki osoitteet ensimmäisenä määritettyyn reittiin, mikä oli tässä tapauksessa ''/''. Ongelman syyksi paljastui yew\char`_routerin Switch-komponentin kokoava ''to'-makro (katso luku \ref{chap:macros}). Ratkaisuna oli reitin ''/'' makron siirtäminen viimeiseksi listassa. Tarkempaa tietoa tästä ongelmasta voi lukea Yew'n dokumentaatiosta \cite{yew:router-problem}.
Asiakaspuolen reitityksen toteutuksen voi nähdä liitteessä \ref{appx:frontend-main}.
@ -196,7 +196,7 @@ Projektin aikana ilmeni muutamia ongelmia, joiden takia projekti vaatii vielä j
\subsection{Evästeet}
\label{sect:problems:cookies}
Palvelinpuolella evästeen kokoava kirjasto, Actixin liitännäinen actix\char`_identity, kirjoittaa oletuksena evästeeseen parametrin \mintinline{JavaScript}{"HttpOnly": true}, mikä tarkoittaa sitä, että selain ei anna sen sisällä suoritettaville ohjelmille pääsyä tähän evästeeseen. Tämä on todella hyvä turvallisuusominaisuus, joka estää haitallisia ohjelmia varastamasta käyttäjän kirjautumistietoja.
Palvelinpuolella evästeen kokoava kirjasto, Actixin liitännäinen actix\char`_identity, kirjoittaa oletuksena evästeeseen parametrin \mintinline{JavaScript}{"HttpOnly": true}, mikä tarkoittaa sitä, että selain ei anna sen sisällä suoritettaville ohjelmille pääsyä tähän evästeeseen. Tämä on hyvä turvallisuusominaisuus, joka estää haitallisia ohjelmia varastamasta käyttäjän kirjautumistietoja.
Suunnittelmana oli käyttää evästeen tietoja asiakaspuolella reititykseen. Esimerkiksi jos evästettä ei ole olemassa, käyttäjä tulee reitittää sisäänkirjautumiskomponenttiin, jossa eväste voidaan noutaa palvelimelta. Koska evästeessä on tämä HttpOnly-parametri, tähän ei ole mahdollisuutta. Tämän parametrin voisi tietysti laittaa pois päältä, mutta actix\char`_identity ei tarjoa tähän mitään mahdollisuutta.