În acest tutorial vom crea un sistem de autentificare în Laravel. Pentru aceasta ne vom folosi de modulul de autentificare al Laravel.
Paşii pe care îi vom urma sunt:
- Configurarea iniţială
- Baze de date, tabele, migrări şi artisan. Prima noastră migrare, tabelul de sesiuni
- Din nou despre migrări, despre schema unui tabel și cum creăm tabelul de utilizatori
- Despre seeding sau cum populezi tabelele dintr-o bază de date
- Despre rute şi crearea lor
- Despre Blade şi cum tăiem cu el template-uri din paginile html
- Realizarea paginii de logare şi a paginii pentru utilizatorii logaţi.
- Administrarea erorilor de logare.
- Folosirea modulului de autentificare pentru validarea utilizatorului.
1. Configurarea iniţială
1.a Setarea bazei de date
Setarea bazei de date se face din fişierul database.php, care se află în app/config. După cum putem vedea, Laravel permite folosirea multor drivere pentru conectarea la baza de date. Noi vom fi mai tradiţionalişti şi vom folosi MySQL pentru baza de date. În fişier, la cheia mysql vom face setările necesare pentru conectarea la baza de date.
'mysql' => array( 'driver' => 'mysql', 'host' => 'localhost', 'database' => 'laravel', 'username' => 'root', 'password' => '', 'charset' => 'utf8', 'collation' => 'utf8_unicode_ci', 'prefix' => '', ),
Asta a fost tot.
1.b Setarea sistemului de autentificare
După cum am spus în introducere, pentru a realiza un sistem de logare în Laravel ne vom folosi de modulul foarte bun oferit de aplicaţie. Acesta se numeşte Authentication şi are o foarte bună documentaţie (http://laravel.com/docs/security) pentru cei ce vor să afle mai multe.
Pentru a ne asigura de cât mai multă siguranţă vom păstra datele de sesiune în baza de date. Pentru a face asta, deschidem fişierul session.php aflat în app/config şi vom modifica driverul folosit.
'driver'=>'database'
După cum putem vedea, sunt mai multe setări în acest fişier:
- lifetime reprezintă valabilitatea în minute a sesiunii în cazul în care nu mai există activitate în sesiunea respectivă; astfel, dacă spre exemplu nu ai fost activ timp de 120 de minute, sesiunea va fi închisă.
- expire_on_close, dacă este setat pe true, îţi permite să ştergi sesiunea în cazul în care utilizatorul închide browser-ul.
- dacă foloseşti driverul nativ pentru păstrarea sesiunilor (fişiere), poţi seta zona unde să se păstreze fişierele de sesiune setând o altă valoare pentru cheia files.
- connection, în cazul în care vrei să foloseşti driverele de sesiune ‘database’ sau ‘redis’, îţi permite să setezi un anumit set de parametri pentru conexiunea la baza de date.
- în cazul în care vrei ca tabelul folosit pentru sesiuni să se numească într-un anumit fel, poţi seta denumirea tabelului completând o valoare la cheia table.
- lottery este un fel de joc de zaruri prin care Laravel hotărăşte la ce actiune a oricarui utilizator va sterge sesiunile vechi.
- cookie este denumirea pentru cookie-ul ce va fi folosit la păstrarea datelor de sesiune.
- domain reprezintă domeniul de valabilitate pentru cookie.
- secure stabileşte dacă cookie-urile vor fi folosite doar pe o conexiune de tip https.
2. Baze de date, tabele, migrări şi artisan. Prima noastră migrare, tabelul de sesiuni
Migrations sau migrări este denumirea generică a modalităţii prin care o aplicaţie se foloseşte de o secvenţă de cod pentru a realiza structura unei baze de date.
“Ce nevoie am eu să mă complic cu migrări? Nu pot pur şi simplu să lucrez cu tabelele în phpMyAdmin?” – acestea sunt în mare nedumeririle celor care aud pentru prima dată de migrations.
Migrările sunt fişiere care, pe lângă faptul că te ajută să fii ordonat în lucrul cu baza de date, îţi şi păstrează o istorie a tuturor modificărilor pe care le-ai făcut tabelelor, permiţându-ţi astfel să te întorci la un anumit episod din filmul schimbarilor facute bazei de date (un fel de version control pentru baza de date).
2.1 “Instalarea” migrărilor
Dacă foloseşti pentru prima data migrări în aplicaţia Laravel va trebui să începi prin a “instala” această facilitate. “Instalarea” nu presupune decât realizarea unui tabel unde Laravel va ţine evidenţa schimbărilor făcute prin aceste migrări.
Lucrul cu migrări se realizează prin intermediul unei unelte a Laravel numită artisan. Artisan este un script PHP care permite o dezvoltare mai rapidă a aplicaţiei prin crearea automatizată a fişierelor care au o structură fixă (dacă îmi permiţi să îmi laud munca, este un fel de Matches pentru Codeigniter).
Cea mai bună explicaţie a unei unelte, cred eu, este să o pui la treabă pentru a vedea ce poate face ea.
Aşadar, considerând că din command prompt (terminal), puteţi rula comenzi php, navighează către root-ul aplicaţiei tale – unde se află şi folderul app (în cazul meu, D:/xampp/htdocs/laravel/). Ajuns acolo scrie:
php artisan list
Dacă în urma execuţiei primeşti o listă de comenzi disponibile, înseamnă ca te afli unde trebuie.
Acum, pentru a crea tabelul migrations, unde va fi păstrată istoria migrărilor, trebuie să scrii:
php artisan migrate:install
Dacă totul decurge normal, vei fi anunţat că s-a creat tabelul migrations.
2.2 Prima noastră migrare: sessions
După crearea tabelului migrations ne putem folosi de această utilitate pentru realizarea, modificarea şi ştergerea din baza de date.
Din fericire, pentru primul nostru tabel nu va trebui să muncim mult, structura tabelului fiind deja gândită de Laravel. Astfel, tot ce trebuie sa scriem pentru realizarea fişierului de migrare este:
php artisan session:table
În urma rulării acestei comenzi vei putea vedea că artisan a creat în folderul app/database/migrations un fişier cu denumirea xxxx_xx_xx_xxxxxx_create_session_table.php (unde x reprezintă o serie de cifre prin care este indicat momentul în timp în care a fost creat fişierul).
Acest fişier va fi folosit de artisan pentru a realiza tabelul.
Dacă deschizi fişierul vei vedea o structură destul de banală. Despre această structură îţi voi vorbi însă când vom realiza tabelul de utilizatori.
Întorcându-ne la linia de comandă, dacă scriem:
php artisan migrate
…rezultatul va fi crearea tabelului în baza de date. Dacă ai cum să vezi tabelele din baza de date (poate cu un phpMyAdmin), te rog să o faci.
3. Din nou despre migrări, despre schema unui tabel si cum creăm tabelul de utilizatori
Acum, că ne-am făcut o idee despre cu ce se mănâncă migrările, să încercăm să facem una de la zero.
Aşadar, aflându-ne în root-ul aplicaţiei cu command prompt-ul, ne vom folosi de artisan pentru a crea un fişier de migrare:
php artisan migrate:make create_users_table --create=users
Hai să analizăm fiecare parametru în parte:
- migrate:make cere artisan-ului să ne creeze un fişier de migrare care să aibă în denumire string-ul “create_users_table“; prin această denumire descriptivă vom şti şi noi la ce se referă migrarea respectivă, fără a mai fi nevoie să ne uităm în fişier; dacă doream să facem un fişier de migrare prin care să adăugăm o coloană nouă la un tabel existent am fi putut da ca nume descriptiv ceva de genul: add_xxx_column_to_users_table, unde xxx ar fi fost denumirea coloanei.
- prin –create=users îi spunem artisan-ului că fişierul de migrare este realizat în vederea creării unui tabel care va purta numele users; dacă am fi dorit să lucrăm cu un tabel existent, am fi putut să dăm ca parametru –table=users.
3.1 Fişierul de migrare
O dată ce i-am dat comanda aceasta, un fişier va fi realizat în folderul app/database/migrations, având în componenţa numelui string-ul “create_users_table“. Dacă îl deschidem, vom vedea ceva de genul:
<?php use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateUsersTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('users', function(Blueprint $table) { $table->increments('id'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::drop('users'); } }
După cum putem vedea, a fost creată o clasă care are două metode:
- up() – metodă cu ajutorul căruia realizăm tabelele.
- down() – metodă cu ajutorul căreia revenim la starea de dinaintea modificărilor realizate prin metoda up.
3.1.1 Realizarea unui tabel
Pentru realizarea tabelului ne vom folosi de metoda create() a clasei Schema. După cum poţi vedea, metoda primeşte ca parametri numele tabelului şi o funcţie anonimă care va returna un obiect de tip Blueprint ce va reprezenta structura tabelului (uau… sper că m-ai înţeles…).
Structura tabelului are deja definite câteva coloane: id-ul şi timestampuri. Hai să mai definim şi noi câteva:
$table->increments('id'); // prima coloana va fi de tip int cu autoincrement si se va numi "id" $table->string('username', 32); // a doua coloana va fi de tip varchar cu o limita de 32 de caractere si se va numi "username" $table->string('email', 150); // a treia coloana va fi de tip varchar cu o limita de 150 caractere si se va numi "email" $table->string('password', 60); // a treia coloana va fi de tip varchar cu o limita de 60 de caractere si se va numi "password" $table->string('remember_token',100)->nullable(); // a patra coloana va fi de tip varchar cu o limita de 100 de caractere si se va numi "remember_token" $table->timestamps(); // timestamps e o functie care va crea doua coloane: created_at si updated_at
Cateva explicaţii suplimentare sunt necesare.
Campului password i-am impus o limită de 60 de caractere deoarece modelul User ce va fi folosit de driverul de autentificare al Laravel-ului va păstra parola criptată prin Bcrypt, ceea ce va rezulta într-o înşiruire de 60 de caractere.
De asemenea, conform documentaţiei pentru driverul Authentication (http://laravel.com/docs/security) este necesară realizarea unei coloane remember_token, de 100 de caractere, unde se va păstrat un token pentru cazul în care vor fi folosite sesiuni de tipul “remember me”.
Aşadar, fişierul de migrare va arăta astfel:
<?php use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateUsersTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('users', function(Blueprint $table) { $table->increments('id'); // prima coloana va fi de tip int cu autoincrement si se va numi "id" $table->string('username', 32); // a doua coloana va fi de tip varchar cu o limita de 32 de caractere si se va numi "username" $table->string('email', 150); // a treia coloana va fi de tip varchar cu o limita de 150 caractere si se va numi "email" $table->string('password', 60); // a treia coloana va fi de tip varchar cu o limita de 60 de caractere si se va numi "password" $table->string('remember_token',100)->nullable(); // a patra coloana va fi de tip varchar cu o limita de 100 de caractere si se va numi "remember_token" $table->timestamps(); // timestamps e o functie care va crea doua coloane: created_at si updated_at }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::drop('users'); } }
3.1.2 Revenirea la starea de dinaintea realizării tabelului
Revenirea la starea de dinaintea realizării tabelului este realizată de metoda drop() a clasei Schema. Prin această metodă spunem artisan-ului să şteargă tabelul din baza de date.
3.2 Artisan şi migrarea în baza de date
O dată ce am realizat fişierul de migrare, nu ne mai rămâne decât să vedem tabelul despre care am vorbit în el realizat în baza de date. Pentru asta scriem comanda:
php artisan migrate
Această comandă spune artisan-ului să se uite în tabelul migrations pentru a vedea ce fişiere a încărcat până în momentul respectiv (în acest caz vorbim de fişierul create_session_table) şi apoi să se uite în folderul app/database/migrations pentru a vedea dacă acolo există fişiere suplimentare faţă de ce are el notat în tabel (în acest caz fişierul suplimentar fiind cel de creare a tabelului de utilizatori). Văzând existenţa unui fişier suplimentar, artisan-ul trece la interpretarea lui şi realizează astfel tabelul users cu coloanele cerute în fişier. După ce a creat tabelul, îşi notează în tabelul migrations că a interpretat acest fişier.
Dacă dorim să revenim la starea de dinaintea realizării tabelului users, putem scrie:
php artisan migrate:rollback
Dacă dorim resetarea bazei de date (ştergerea tuturor tabelelor definite în fişierele de migrare), putem scrie:
php artisan migrate:reset
Dacă dorim refacerea de la zero a tabelelor pe baza fişierelor de migrare (un fel de migrate:reset+migrate), scriem:
php artisan migrate:refresh
În speranţa că totul a mers OK, vom trece mai departe la episodul următor…
4. Despre seeding sau cum populezi tabelele dintr-o bază de date
Pe lângă migrări, Laravel îţi permite şi popularea bazelor de date. Pentru aceasta se foloseşte de clasa DatabaseSeeder care extinde clasa Seeder şi poate fi găsită în folderul app/database/seeds. După cum poţi vedea, clasa are o singură metoda: up(). De asemenea, comentată, vei găsi o linie care cheamă clasa UserTableSeeder.
Vom scoate comentariul, lăsând astfel linia să poată fi citită şi vom crea în acelaşi folder un fişier cu numele UserTableSeeder.php.
În acesta vom scrie:
<?php class UserTableSeeder extends Seeder { public function run() { DB::table('users')->delete(); User::create(array( 'username' => 'admin', 'email' => 'admin@exemplu.ro', 'password' => Hash::make('parola'), )); } }
În mare, cerem clasei DatabaseSeeder să ruleze clasa UserTableSeeder, clasă care şterge toate înregistrările din tabelul users şi apoi îl populează cu înregistrarea/înregistrările pe care o/le definim într-un array. După cum poţi vedea, parola va fi deja criptată când va intra în baza de date (folosind clasa Hash), rezultând un hash de 60 de caractere.
Acum, după ce ne-am realizat înregistrările necesare pentru tabel, va trebui să populăm tabelul respectiv şi vom face asta folosindu-ne din nou de Artisan. Astfel, aflându-ne în root-ul aplicaţiei vom scrie în command prompt/terminal:
php artisan db:seed
Această comandă ar trebui să populeze baza de date. Te rog să verifici dacă Laravel şi-a făcut din nou datoria…
Despre rute şi crearea lor
Rutele sunt o parte importantă a Laravel, toate interacţiunile cu utilizatorii realizându-se prin intermediul acestora.
Cu alte cuvinte, rutele definesc destinaţiile către care sunt trimişi utilizatorii în momentul în care aceştia fac o cerere către aplicaţie. Aşadar, în momentul în care un utilizator dă clic pe un link, aplicaţia apelează la app/routes.php pentru a vedea cărui controller şi cărei metode să trimită cererea respectivă.
Prin urmare, fişierul routes.php este una dintre cele mai importante elemente ale dezvoltării unei aplicaţii cu Laravel.
Dacă ne uităm în app/routes.php, vom vedea ceva de genul:
Route::get('/', function() { return View::make('hello'); });
Prin aceste linii, aplicaţiei i se spune că în momentul în care este apelat root-ul aplicaţiei (“/”), aplicaţia va trebui să returneze un view numit hello.
Ne putem face o idee despre cum funcţionează rutele:
- get este metoda prin care se face cererea. Aşa cum PHP-ul interpretează metode de cerere http precum ‘GET’, ‘HEAD’, ‘POST’, ‘PUT’, tot aşa şi Laravel are definite metode prin care poate interpreta cererile. Cele mai populare cereri http sunt folosite de Laravel sunt:
- get – pentru afişarea unei pagini
- post – pentru trimiterea de date prin formular
- put – pentru salvare
- patch – pentru modificare de informaţii
- delete – pentru ştergere de informaţii
- “/” reprezintă linkul care va fi adresat în cadrul rutei. În acest caz este vorba de accesarea root-ului aplicaţiei (homepage-ul).
- function() – reprezintă o funcţie anonimă, rutei returnându-i-se direct ceea ce s-a definit în cadrul funcţiei anonime.
Pentru a lucra cu rute, noi le vom modifica puţin. În primul rând, să vedem de ce “pagini” vom avea nevoie. Pentru început vom avea nevoie de:
- login – cerere de tip get pentru accesarea paginii care va avea formularul de logare.
- login – cerere de tip post pentru trimiterea către aplicaţie a datelor de logare şi interpretarea acestora
- secure – pagină unde vor avea acces doar utilizatorii logaţi
- logout – cerere de tip get pentru accesarea paginii care va permite delogarea utilizatorilor
Pentru moment, aceste rute ne sunt de ajuns. Dacă vom mai avea nevoie de altele, le vom adăuga pe parcurs.
Vom încerca să definim rutele cât mai la obiect, evitând astfel situaţiile în care să existe rute care să trimită către controllere sau metode inexistente.
Route::get('/login', array('as'=>'login','uses'=>'UserController@index')); // la accesarea "paginii" login prin metoda GET, router-ul va trimite vizitatorul la controllerul UserController, metoda index(). De asemenea, dam un nume rutei respective: 'login'. Route::post('/login', array('as'=>'login','uses'=>'UserController@login')); // la accesarea "paginii" login prin metoda POST, router-ul va trimite vizitatorul la controllerul UserController, metoda login(). A se vedea ca, desi are acelasi nume, ruta "login" se va referi in acest caz la metoda POST. Route::get('/secure', array('as'=>'securepage','uses'=>'SecurePageController@index')); // pagina secure, unde vor avea acces doar persoanele logate. Route::get('/logout', array('as'=>'logout','uses'=>'UserController@logout')); // pagina de logout... Route::get('/', function() { return View::make('hello'); });
Acum, după ce am definit rutele, tot ce ne rămâne de făcut sunt views, controllerele şi metodele.
Despre Blade şi cum tăiem cu el template-uri din paginile html
În realizarea aplicaţiei, ar trebui ca următorul pas să fie realizarea controllerelor, cu metodele aferente. Cu toate acestea, în interesul acestui tutorial, voi începe prin realizarea template-urilor de pagină, urmând apoi să facem view-urile aferente şi controllerele.
Aşadar, cum facem un view? Ne vom folosi de Blade, un motor de templating care vine împreună cu Laravel. Template-urile realizate cu blade ar trebui să aibă extensia .blade.php.
Structura unei pagini html
Vom împărţi pagina html în:
– master.blade.php – acesta va fi fişierul care va uni toate părţile componente ale unei pagini;
– head.blade.php – aici vom pune codul paginii pana la tagul de închidere al <head>-ului;
– header.blade.php – aici vom pune codul paginii ce va ţine headerul (logo-ul site-ului, meniul orizontal etc.);
– footer.blade.php – aici vom pune eventualele tag-uri de închidere a div-urilor paginii şi cam tot ce ţine de display-ul footer-ului unei pagini;
– foot.blade.php – aici vom pune eventualele scripturi javascript şi orice ţine de acestea.
Toate fişierele le vom salva în folder-ul views/layouts/admin (presupunând că în viitor vom avea un layout separat pentru front-end…).
master.blade.php
După cum am spus, master.blade.php va fi fişierul care va uni toate părţile componente ale unei pagini. Fişierul va arăta astfel:
@include('layouts.admin.head') <body> <div class="container"> @include('layouts.admin.header') @yield('content') @include('layouts.admin.footer') </div> @include('layouts.admin.foot') </body> </html>
Prin tag-ul @include, îi spunem lui Blade că dorim spre exemplu ca în zona respectivă să includă fişierul head.blade.php care se regăseşte în folder-ul layouts/admin. A se vedea faptul că Blade interpretează semnul “.” ca un “/” şi că nu trebuie să scriem extensia atunci când chemăm fişierul.
De asemenea, prin tag-ul @yield, spunem lui Blade să creeze o secţiune al cărei conţinut va fi creat ulterior.
head.blade.php
@section('main_head') <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Aplicatie</title> <!-- Bootstrap --> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css"> <!--[if lt IE 9]> <script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script> <script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script> <![endif]--> @show </head>
După cum poţi vedea, aici apar două tag-uri: @section şi @show. Acestea puteai foarte bine să nu le mai incluzi, dar cu toate acestea, este foarte bine să le incluzi. Ce fac aceste tag-uri? Ele pur şi simplu îţi vor permite ca ulterior, după acest bloc de cod să introduci un alt cod. Cu alte cuvinte, dacă într-o pagină vei avea nevoie să introduci un alt css sau un javascript înainte de închiderea <head>-ului vei putea face ceva de genul:
@section('main_head') @parent <link rel="stylsheet" href="..." /> @stop
La fel vom face şi în footer si in foot, pentru a acoperi situaţiile în care secvenţe de cod sau scripturi chemate sunt valabile numai pentru anumite pagini.
header.blade.php
<h1>Nume aplicatie</h1>
footer.blade.php
@section('footer') <div class="col-lg-12 text-center"> © Aplicatie {{ date('Y') }} - Powered by <a href="http://laravel.com">Laravel</a> </div> @show
Blade interpreteaza secvenţa dintre acolade {{…}} drept un <?php echo “…” ;?>
foot.blade.php
@section('foot') <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script> @show
Acum urmează să facem un controller pentru a verifica cum se afişează template-ul.
migrate:make nu este corecta
Poate mai sunt si alte comenzi care trebuie actualizate.
Ei? Cum asa? Dupa cum vezi tutorialul este pentru Laravel 4.2. De ce zici ca “nu este corecta”?
Ma gandeam ca actualizezi tutorialul pentru 5.2.29
La pc 4 Despre seeding -nu gaseste clasa Seeder.