Storybook

Sorakuilu

Harjoituksen osat

Tunti 1. Toimeksianto ja storybook-sovelluksen esitutkimus
Tunti 2. Suunnittele storybook
Tunti 3. Toteuta tietokanta
Tunti 4. Toteuta käyttöliittymä
Tunti 5. Laadi runko ja reititys järjestelmään
Tunti 6. Toteuta lukijan etusivu (tietojen haku lukijan näkymässä)
Tunti 7. Toteuta rekisteröityminen(tietojen lisäys lukijan näkymässä)
Tunti 8. Toteuta autentikointi (kirjaudu ja kirjaudu ulos)
Tunti 9. Toteuta ylläpidon etusivu (tietojen haku)
Tunti 10.Toteuta jutun lisäys ylläpitonäkymässä, tietojen tarkistus mukaan
Tunti 11.Toteuta jutun muokkaus ylläpitonäkymässä, tietojen tarkistus mukaan
Tunti 12.Toteuta jutun poistaminen ylläpitonäkymässä
Omat tehtävät: suunnittele ja toteuta admin-näkymän yhden jutun näyttäminen (linkki on jo olemassa), omien tietojen muokkaaminen sekä salasanan vaihtaminen (piirrä lisäksi kaaviot)


Tunti 8. Toteuta autentikointi (kirjaudu ja kirjaudu ulos)

Kirjautumisen ideana on tallentaa kirjautumistietojen tarkistamisen jälkeen istunnon id ja käyttäjän id account_sessions-tauluun.

Kun käyttäjä tekee kirjautumista vaativan pyynnön järjestelmälle, tarkistetaan istunnon olemassaolo ja istunnon ikä account_sessions-taulusta.

Uloskirjautuessa poistetaan istunto taulusta.

Kirjautumisen yhteydessä User-luokan olio saa arvot name ja id, jotka poistetaan, kun kirjaudutaan ulos.

Tämän tunnin tehtävät

toteutettavat osat

Kuvassa näkyvät tässä vaiheessa tarvittavat osat, jo toteutetut ovat harmaalla pohjalla.

Alla oleva sekvenssikaavio kuvaa periaatetta - tarkemmin kuvattaessa kannattaa käyttää metodien ja muuttujien nimiä:

Kirjautuminen

sekvenssikaavio

Päivitetään User-luokkaa, lisätään metodit

public function login(string $name, string $passwd): bool

Metodi tarkistaa ensin, onko tietokannassa käyttäjää, jonka name on sama kuin parametrinä annettu nimi ja account_enabled on true.

Jos name löytyy, metodi tarkistaa, vastaavatko salasanat toisiaan (password_verify).

Jos molemmat tarkistukset onnistuvat, metodi asettaa olion $user name-arvoksi nimen ja id:n arvoksi id:n, kutsuu registerLoginSession-metodia tallentamaan istunnon account_sessions-tauluun sekä palauttaa arvon true, muuten se palauttaa arvon false.

<?php 
    
public function login(string $namestring $passwd): bool
    
{
        global 
$db;
                
        
/* Look for the account in the db. Note: the account must be enabled (account_enabled = 1) */
        
$query 'SELECT * FROM users WHERE (account_name = :name) AND (account_enabled = 1)';
        
        
/* Values array for PDO */
        
$values = array(':name' => $name);
        try
        {
            
$res $db->prepare($query);
            
$res->execute($values);
        }
        catch (
PDOException $e)
        {
           
/* If there is a PDO exception, throw a standard exception */
           
throw new Exception('Database query error');
        }
        
        
$row $res->fetch(PDO::FETCH_ASSOC);
        
        
/* If there is a result, we must check if the password matches using password_verify() */
        
if (is_array($row))
        {
            if (
password_verify($passwd$row['account_passwd']))
            {
                
/* Authentication succeeded. Set the class properties (id and name) */
                
$this->id intval($row['account_id'], 10);
                
$this->name $name;
                
                
/* Register the current Sessions on the database */
                
$this->registerLoginSession($db);
                
                
/* Finally, Return TRUE */
                
return TRUE;
            }
        }
        
/* If we are here, it means the authentication failed: return FALSE */
        
return FALSE;

    }
?>

private function registerLoginSession($db)

Jos on olemassa aktiivinen istunto, metodi poistaa account_sessions-taulusta vanhat istunnot, joilla on sama id kuin nykyisellä sekä tallentaa istunnon id:n (session_id() ja käyttäjän id:n account_sessions-tauluun)

<?php
/* Saves the current Session ID with the account ID */
    
private function registerLoginSession($db)
    {
        
/* Check that a Session has been started */
        
if (session_status() == PHP_SESSION_ACTIVE)
        {
            
/* Poista vanha istunto, jolla on sama id kuin nykyisellä*/
            
$query 'DELETE FROM account_sessions WHERE (session_id =:sid)';
            
$values = array(':sid' => session_id());
            try
            {
                
$res $db->prepare($query);
                
$res->execute($values);
            }
            catch (
PDOException $e)
            {
               throw new 
Exception('Database query error');
            }
            
/* Lisää nykyisen istunnon id*/
            
$query "INSERT INTO account_sessions(session_id, account_id) VALUES (:sid, :id)";
            
$values = array('sid' => session_id(),':id' =>$this->id);
            try
            {
                
$res $db->prepare($query);
                
$res->execute($values);
            }
            catch (
PDOException $e)
            {
               throw new 
Exception('Database query error');
            }
        }
    }
?>

public function logout()

Jos on olemassa aktiivinen istunto, metodi poistaa ko. istunnon account_sessions -taulusta ja asettaa tietojäsenet $id ja $name tyhjiksi.

<?php    
    
public function logout()
    {
        global 
$db;
        
        if (
session_status() == PHP_SESSION_ACTIVE)
        {
            
/* Delete query */
            
$query 'DELETE FROM account_sessions WHERE (session_id = :sid)';
            
$values = array(':sid' => session_id());
            try
            {
                
$res $db->prepare($query);
                
$res->execute($values);
            }
            catch (
PDOException $e)
            {
               throw new 
Exception('Database query error');
            }
        }
        
        
$this->id NULL;
        
$this->name NULL;
    }
?>

public function sessionLogin($db): bool

Tarkistaa onko käyttäjä kirjautunut, palauttaa arvon true tai false.

Alla on sekvenssikaaviossa periaate viestintään:

sekvenssikaavio

Jos on olemassa aktiivinen istunto, metodi tarkistaa account_sessions -taulusta, onko olemassa tietuetta:

Jos kaikki ehdot täyttyvät, metodi palauttaa true, muuten false. Käyttäjä on siis kirjautuneena järjestelmässä, jos metodi palauttaa truen.

<?php
    
public function sessionLogin()
    {
        global 
$db;
        
        if (
session_status() == PHP_SESSION_ACTIVE)
        {
            
$query 
            
            
"SELECT * FROM account_sessions, users WHERE (account_sessions.session_id = :sid) AND (account_sessions.login_time >= (NOW() - INTERVAL 7 DAY)) AND (account_sessions.account_id = users.account_id) AND (users.account_enabled = 1)";
            
            
$values = array(':sid' => session_id());
            
            try
            {
                
$res $db->prepare($query);
                
$res->execute($values);
            }
            catch (
PDOException $e)
            {
               throw new 
Exception('Database query error');
            }
            
            
$row $res->fetch(PDO::FETCH_ASSOC);

            if (
is_array($row))
            {
                
/* Authentication succeeded. Set the class properties (id and name) and return TRUE*/
                
$this->id intval($row['account_id'], 10);
                
$this->name $row['account_name'];
                
                return 
TRUE;
            }
        }
        
        
/* If we are here, the authentication failed */
        
return FALSE;
    }
?>

Reititys

Jotta istuntoa voi käyttää, tulee aloittaa ennen html:n tulostusta: lisätään siis session_start() tiedoston alkuun.

Lisätään index.php -tiedostoon reitit kirjautumislomakkeeseen, kirjautumisen tarkistamiseen ja uloskirjautumiseen.

<?php
session_start
(); // for authentication
/****************lisää ylläoleva istunnon aloitus*************/

require './Route.php'// routing class
require './database/db.php'// database connection

require './controllers/storyController.php';
$storyController = new StoryController();

require 
'./controllers/userController.php';
$userController = new UserController();


//every route gets its own controller or view
Route::add('/',function() {
    global 
$storyController;
    
$storyController->index();    
},
'get');


Route::add('/register/',function() {
    require 
'./views/registerform.view.php';
},
'get');

Route::add('/register/',function() use ($userController,$user) {
    
$userController->register();
},
'post');


/********* LISÄÄ SEURAAVAT *****************
$user luodaan, kun luodaan uusi userController-olio, välitetään $userControllerin sisällä, ja koska se on protected, tarvitaan metodi getUser() sen hakemiseen */

Route::add('/login/',function() {
    require 
'./views/loginform.view.php';
},
'get');


Route::add('/login/',function() use ($userController) {
    
$userController->login($userController->getUser());
},
'post');


Route::add('/logout/',function() use ($userController) {
    
$userController->logout($userController->getUser());
},
'get');
/********************************************/

//start...
Route::run('/');

?>

Muokataan kontrolleria ./controllers/userController.php

userController-luokkaan lisätään metodit getUser(), login() ja logout().

public function getUser()

Metodi palauttaa käyttäjän tiedot (huom. koska tiedot ovat private-määreisiä, niitä ei voi hakea suoraan ilman erillistä metodia.

login()

Metodi tarkistaa ja puhdistaa (sanitize ja validate) lomakkeen tiedot, kutsuu User-luokan kirjautumismetodia ja kirjautumisen onnistuessa sisällyttää admin-etusivun.

Jos kirjautuminen ei onnistu, se sisällyttää kirjautumislomakkeen.

logout()

Metodi kutsuu User-luokan uloskirjautumismetodia ja hakee lukijan etusivuun tarvittavat tiedot tietokannasta sekä sisällyttää sen jälkeen lukijan etusivun.

<?php

require './database/models/User.php'// user management for authentication

class UserController
{
    protected 
$user;
    
    public function 
__construct()
    {
        
$this->user = new User();
    }
    


    public function 
register()
    {
        require 
"./helpers/helper.php";

        if(isset(
$_POST["account_name"],$_POST["password1"],$_POST["password2"],$_POST["last_name"],$_POST["first_name"]) && $_POST["password1"]==$_POST["password2"]){
        
$password=sanitize($_POST["password1"]);
        
$account_name=$_POST["account_name"];
        
$last_namesanitize($_POST["last_name"]);
        
$first_namesanitize($_POST["first_name"]);

        
$password password_hash($passwordPASSWORD_DEFAULT);

        
$newAccount=$this->user->addAccount($last_name,$first_name$account_name,$password);
        
        require 
'./views/registered.view.php';
        } else {
            
$message ="Tarkista salasanat";
            require 
'./views/registerform.view.php';
        }
    }
    
/*******************LISÄÄ SEURAAVAT ***************/
    
    
public function getUser() 
    {
        return 
$this->user;
    }
    
    public function 
login($user)
    {
        require 
'./helpers/helper.php';
    
        if(isset(
$_POST["account_name"], $_POST["password"])) {
        
$name=sanitize($_POST["account_name"]);
        
$password=sanitize($_POST["password"]);
        }

        if(
$user->login($name,$password)) {
            require 
'./views/admin.view.php';
        }
        else {
            
$message ="Tarkista käyttäjätunnus ja salasana";
            require 
'./views/loginform.view.php';
        }
    }
    
    public function 
logout($user)
    {
        
$user->logout();
        
$stories Story::get_last_five_stories_and_name();
        require 
'./views/index.view.php';
    }
}    
?>
    
    

./views/loginform.view.php

<?php
require './views/partials/head.php';
?>

<form action="/login/" method="post">
<h2>Kirjaudu</h2>
<?php if(isset($message)) echo $message;?>
<p>
<label for="account_name">Käyttäjätunnus</label><br>
<input type="text" name="account_name"><br>
</p>

<p>
<label for="password">Salasana</label><br>
<input type="password" name="password"><br>
</p>

<p>
<input class="button" type="submit" value="Kirjaudu">
</p>
</form>


<?php
require './views/partials/end.php';
?>

./views/admin.view.php

<?php
require './views/partials/admin_head.php';

echo 
"Tästä tulee admin.view.php";

require 
'./views/partials/admin_end.php';
?>


>> Tunti 9. Toteuta ylläpidon etusivu (tietojen haku) >>