\chapter{Projekti}
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.

\begin{figure}[h]
  \centering
  \includegraphics[width=\linewidth]{illustration/Architecture.pdf}
  \caption{Projektin arkkitehtuurimalli}
  \label{fig:architecture}
\end{figure}

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

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

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}
Palvelinpuolen kehykseksi valikoitui Actix web. Se on käytännössä vastine JavaScript-maailman Express.js:lle, eli se hoitaa HTTP-palvelimen työtä ja reitittää GET- ja POST-pyynnöt ohjelman oikeille funktioille.

Actix web on puolestaan rakennettu hyödyntämällä Actix-sovelluskehystä, joka on rakennettu löyhästi actor-mallin pohjalta. Actor-malli \cite{wiki:actor} on Carl Hewittin vuonna 1973 luoma matemaattinen ja tietotekninen malli rinnakkaisajosta. Tämän ansiosta Actix web on hyvin suorituskykyinen ja helposti skaalautuva ratkaisu rajapintoja rakennettaessa.

Actix web on myös hyvin integroitu Rustin vahvaan tyypitykseen. Erityisen vaikuttavaa oli se, että esimerkiksi tietyn rajapinnan päätepisteen POST-pyyntöön pystyy määrittämään parametriksi tietyn rakenteen (eng. structure) [koodiesimerkki \ref{code:rust:registeruser}].

\clearpage

\begin{code}
	\inputminted{Rust}{code/registeruser.rs}
	\captionof{listing}{Rakenne POST-pyynnön parametrinä}
	\label{code:rust:registeruser}
\end{code}

Tällöin varmistutaan automaattisesti siitä, että kun asiakkaan POST-pyyntö saapuu tähän funktioon, kaikki data on oikeanlaista tyyppiä ja kaikki tarvittava data on pyynnössä mukana. Verrattuna JavaScriptiin, jossa ei ole tyyppejä, kaikki vastaanotettava data pitäisi tarkastaa käsin.

\begin{code}
	\inputminted{JSON}{code/registeruser.json}
	\captionof{listing}{Rakenteeseen sovitettava JavaScript-objekti}
	\label{code:json:registeruser}
\end{code}

Kun koodiesimerkin \ref{code:rust:registeruser} funktioon ''register'' saapuu koodiesimerkin \ref{code:json:registeruser} mukainen JSON-objekti, Actix huomaa väärän tyypin ja vastaa statuskoodilla ''400 Bad Request'', koska objektin parametri \mintinline{JSON}{"admin"} ei ole tyyppiä \mintinline{Rust}{bool}.

Palvelinpuolen initialisointi ja käynnistäminen löytyvät liitteestä \ref{appx:actix}.

\subsection{Todentaminen}

Actix webin modulaarisuus mahdollisti myös tarvittavien väliohjelmistojen (eng. middleware) sisällyttämisen ohjelman toimintaan. Actix identity -paketista löytyi tarvittavat palikat, joilla sain lisättyä itse kirjoittamani käyttäjän todentamistoiminnallisuuden suojaamaan haluttuja reittejä.

Todentamiseen päätin käyttää JSON Web Tokeneita. Ne ovat standardoitu (RFC 7519\cite{jwt:home}) tunnistautumistapa verkossa. Tokenit ovat merkkijonoja, jotka sisältävät JavaScript-objekteja tekstimuodossa (JSON). Token koostuu kolmesta osasta \cite{jwt:home}: ylätunnisteesta (eng. header), hyötykuormasta (eng. payload) ja allekirjoituksesta (eng. signature). JSON Web Tokenin kaikki osat on havainnollistettu kuvassa \ref{fig:jwt}.

\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}}
  \label{fig:jwt}
\end{figure}

\bigskip

Ylätunniste koostuu JSON-objektista [koodiesimerkki \ref{code:json:jwt-header}], missä on määritelty tokenin tyyppi (tässä tapauksessa "JWT") ja allekirjoituksen algoritmi, mikä voi olla joko HS256 tai RSA.

\begin{code}
	\inputminted{Rust}{code/jwt-header.json}
	\captionof{listing}{JSON Web Tokenin ylätunniste}
	\label{code:json:jwt-header}
\end{code}

\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ä, 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

\begin{code}
	\inputminted{Rust}{code/jwt.json}
	\captionof{listing}{Yhden JSON Web Tokenin hyötykuorma tästä projektista}
	\label{code:json:jwt}
\end{code}

\bigskip


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.

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.

Päätin tallettaa edellä mainitun JSON Web Tokenin evästeeseen (eng. cookie), joka on standardi tapa tallettaa juuri tällaisia todentamiseen käytettäviä tietoja selaimissa. Evästeiden käyttämisen etu on se, että selain huolehtii sen tallettamisesta automaattisesti ilman lisätoimia kehittäjältä. Lisäksi selain sisällyttää sen seuraaviin kutsuihin automaattisesti.

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 muun muassa CSS-tyylimääritykset, kuvat ja JavaScript-ohjelmat.

\begin{figure}[h]
  \centering
  \includegraphics[width=\linewidth]{illustration/CORS.pdf}
  \caption{Esimerkki Single origin policy -turvallisuuskäytännöstä}
  \label{fig:cors}
\end{figure}

Kuvassa \ref{fig:cors} käyttäjä navigoi osoitteeseen ''palvelin1.fi'', josta selain lataa HTML-dokumentin. Tässä dokumentissa on kaksi kuvaa, ''kuva1.jpg'' ja ''kuva2.png''. Kuva 1 tulee samalta palvelimelta kuin mistä dokumenttikin, joten selain sallii sen lataamisen SOP-käytännön mukaisesti. Kuva 2 taas tulee toiselta palvelimelta, joten selain estää sen lataamisen.

Lähes kaikki nykyiset web-ohjelmistot kuitenkin vaativat näiden ulkoisten resurssien käyttöä. CORS on tekniikka, jossa palvelin kertoo selaimelle sallitut osoitteet, mistä resursseja saa noutaa. 

Jotta kuvan 2 lataaminen saataisiin toimimaan, palvelimen tulee implementoida CORS-tekniikka. Palvelimen tulee lähettää asiakkaalle HTML-dokumentin yhteydessä ylätunniste [koodiesimerkki \ref{code:cors:header}], joka sisältää palvelimen 2 osoitteen. Näin käyttäjän selain tietää, että palvelin 1 sallii resurssien noutamisen palvelimelta 2.

\bigskip

\begin{code}
	\inputminted{shell}{code/cors-header}
	\captionof{listing}{Esimerkki CORS-ylätunnisteesta}
	\label{code:cors:header}
\end{code}

CORS:n lisääminen tähän projektiin hoitui Actixin liitännäisellä actix\char`_cors. CORS:n asetusten määritys löytyy liitteestä \ref{appx:actix}.

\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}
  \caption{Tietokannan ER-malli}
  \label{fig:er-model}
\end{figure}

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: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.

\section{Asiakaspuoli}
\subsection{Asennus}
\label{sect:asiakaspuoli:asennus}
Projektin asiakaspuolen aloittaminen vaati aika paljon tutkimustyötä. Rust-koodi pitää kääntää WebAssemblyksi, johon on olemassa useita eri työkaluja. Lisäksi selaimien rajapintojen käyttämiseen tarvitsee jonkinlaisen kirjaston, joita Rust-maailmassa on tällä hetkellä kaksi: stdweb\cite{webassembly:stdweb} ja web\char`_sys\cite{webassembly:websys}. Näistä stdweb on vanhempi, mutta myös tuetumpi. web\char`_sys on uudempi tulokas ja näyttää siltä, että se tulee korvaamaan stdweb:n tulevaisuudessa.

Valitsemani sovelluskehys tukee molempia kirjastoja, mutta päädyin kuitenkin valitsemaan stdweb:n. Suurimpana syynä oli projektin aloittamisen helppous, joka tehdään Cargon liitännäisellä cargo-web. Toisena syynä oli, että WebAssembly-ohjelman paketointi web\char`_sys:n kanssa on tätä kirjoittaessani riippuvainen NodeJS:stä, kun taas stdweb ei vaadi NodeJS:n asennusta kehittäjän koneelle ollenkaan.

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.

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

\begin{figure}[h]
  \centering
  \includegraphics[width=\linewidth]{illustration/login.png}
  \caption{Login-komponentin tyylittely, joka on toteutettu käyttämällä UIKit-kirjastoa}
  \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ä.

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

Asiakaspuolen reitityksen toteutuksen voi nähdä liitteessä \ref{appx:frontend-main}.

\section{Ongelmat}
Projektin aikana ilmeni muutamia ongelmia, joiden takia projekti vaatii vielä jatkokehitystä.

\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 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.

Yhtenä ratkaisuna tähän ongelmaan olisi käyttää JSON Web Tokenin tallettamiseen evästeen sijasta selaimen LocalStoragea. Tämä vaatisi lisää työtä sekä asiakaspuolella että palvelinpuolella.

\subsection{Tietokantayhteys}
Palvelimen ja tietokannan välisessä yhteydessä oli koko projektin ajan ongelma, että jokainen kysely tietokantaan kesti noin viisi sekuntia. Luulen että tämä ongelma liittyy jotenkin käyttämääni yhteyksien yhdistämiseen [luku \ref{project:database}], koska palvelimen loki näyttää satunnaisesti virheviestin \mintinline{shell}{Failed to create DB pool: Error(Some("Too many connections")}. Asian selvittäminen jää jatkokehitykseen.

\section{Tulokset}
Tuloksena syntyi yksinkertainen web-ohjelma, jossa on toimiva sisäänkirjautumistoiminallisuus. Sen avulla asiakas voi noutaa palvelimelta suojattua dataa. Kuvassa \ref{fig:login-process} on määritelty kaikki kirjautumisprosessin vaiheet.

\begin{figure}[h]
  \centering
  \includegraphics[width=\linewidth]{illustration/login-process.pdf}
  \caption{Kirjautumisprosessi projektissa}
  \label{fig:login-process}
\end{figure}


Ohjelman juuressa renderöidään komponentti ''ProtectedComponent'', missä on yksi nappi, jolla voidaan noutaa dataa palvelimelta. Tämä data on suojattu niin, että pyynnön mukana pitää olla eväste, jonka sisällä on JWT, joka sitten validoidaan palvelinpuolella. Jos validointi onnistuu, suojattu data lähetetään asiakkaalle. Asiakaspäässä HTTP-statuskoodin perusteella näytetään joko noudettu data, tai "403 Unauthorized".

Reitissä ''/login'' renderöidään ''LoginComponent'', joka koostuu kahdesta tekstikentästä, käyttäjänimi ja salasana, sekä napista, jolla kirjautumistiedot voi lähettää palvelimelle. Onnistumisen kirjautumisen jälkeen palvelimelta lähetetty eväste tallennetaan selaimen muistiin.

Luvussa \ref{sect:problems:cookies} mainittujen ongelmien takia toteutus jäi hieman kesken. Eväste saadaan onnistuneesti palvelimelta selaimeen, mutta koska eväste ei ole ohjelman saatavilla, en voi toteuttaa tämän perusteella reititystä uudelle sivulle. Tein tämän takia sivun ylälaitaan napit, joilla käyttäjä voi siirtyä manuaalisesti sivulta toiselle. Ajatuksena oli, että onnistuneen kirjautumisen jälkeen käyttäjä siirrettäisiin toiselle sivulle, ja evästeen puuttueessa taas kirjautumissivulle.
