Laravel Authentication und Authorization Beispiel
Laravel ist für Benutzer-Anmeldungen bereits vorbereitet, das Aktivieren der Funktion erfolgt mit einem einfachen Befehl.
Vorbereitung Laravel/ui
Als Vorbereitung wird für die Bootstrap-Files laravel/ui benötigt:
composer require laravel/ui
php artisan ui bootstrap
Authentifizierung hinzufügen
Der Befehl: php artisan ui vue --auth
(seit Laravel 6.0, für Laravel 5.x php artisan make:auth)
installiert alle Voraussetzungen für eine Benutzeranmeldung
vagrant@homestead:~/Code/Laravel$ php artisan make:auth
Created View: /home/vagrant/Code/Laravel/resources/views/auth/login.blade.php
Created View: /home/vagrant/Code/Laravel/resources/views/auth/register.blade.php
Created View: /home/vagrant/Code/Laravel/resources/views/auth/passwords/email.blade.php
Created View: /home/vagrant/Code/Laravel/resources/views/auth/passwords/reset.blade.php
Created View: /home/vagrant/Code/Laravel/resources/views/auth/emails/password.blade.php
Created View: /home/vagrant/Code/Laravel/resources/views/layouts/app.blade.php
Created View: /home/vagrant/Code/Laravel/resources/views/home.blade.php
Created View: /home/vagrant/Code/Laravel/resources/views/welcome.blade.php
Installed HomeController.
Updated Routes File.
Authentication scaffolding generated successfully!
vagrant@homestead:~/Code/Laravel$
Die Javascript-Sourcen sollten mit "npm run dev" kompiliert werden.
Die Standard-Welcome-View,
wird mit mit der Application's Landing Page ersetzt:
Der Befehl erzeugt die notwendigen Views, einen "HomeController" und die Datei: routes\web.php wird um folgende Einträge erweitert:
Auth::routes();
Route::get('/home', 'HomeController@index');
Fortsetzung zum Myinput-Beispiel
Wer unserem Beispiel Laravel 5 Beispiel - Schritt für Schritt gefolgt ist, bekommt die zuvor erstellte Datei /layouts/app.blade.php ersetzt,
unsere Demo-App /myinputs ist aber immer noch öffentlich, also ohne einer Benutzeranmeldung, verfügbar:
Controller nur für authentifizierte Benutzer
Der Controller "MyinputController" kann mit folgender Konstruktormethode nur für authentifizierte Benutzer erlaubt werden:
public function __construct()
{
$this->middleware('auth');
}
<?php
namespace App\Http\Controllers;
use App\Myinput;
use View;
use Illuminate\Http\Request;
use App\Http\Requests;
class MyinputController extends Controller
{
public function __construct()
{
$this->middleware('auth');
}
Beim Aufruf unseres Beispiels: http://TESTURL/myinputs werden wir automatisch zur Anmeldung umgeleitet.
Damit nach der Anmeldung nicht die Standard-Home-View kommt, können wir die Routes anpassen. Dadurch kommt anstelle des Home-Controllers unsere bereits erstellte Übersichtseite. Dazu ändere ich in der Datei routes/web.php folgende Zeile:
Route::get('/home', 'HomeController@index');
auf:
Route::get('/home', 'MyinputController@index');
Authorization
Des weiteren ist es möglich, dass nur bestimmte Benutzer, bestimmte Funktionen aufrufen können: Authorization.
Für die Demonstration dieser Funktion, erweitere ich die Users-Tabelle in der Datenbank mit der Spalte "role_id". Ziel ist es, dass nur bestimmte Benutzer die Rechte für das Erstellen und Bearbeiten der Einträge bekommen (Admin). Die Benutzertabelle wird dazu um einen Wert erweitert: role_id.
Benutzer mit allen Rechten bekommen die: role_id=1, alle anderen: role_id=0. Das Beispiel dient dem Verständnis, für grössere Werbeprojekte empfehle ich das Paket laravel-permission.
Erweitern einer Datenbanktabelle
Eine Datenbank sollte im Nachhinein nicht direkt über PHP-Myadmin geändert werden, sondern mit einer Migration. Mit Hilfe der Migrationsdateien können Änderungen an der Applikation nachvollzogen und die Datenbank kann daraus jederzeit neu generiert werden.
Ich erzeuge also eine neue Migrations-Datei für das Hinzufügen der Spalte: role_id:
user@rechner /var/www/html/systeme/testapp $ php artisan make:migration add_column_to_users
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddColumnToUsers extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('users', function($table)
{
$table->integer('role_id')->default('0');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('users', function($table)
{
$table->dropColumn('role_id');
});
}
}
Die Funktion up fügt die Spalte hinzu, down könnte diese bei einem "Rollback" wieder entfernen.
Ausführen der Migration
Damit die Änderung in der Datenbank übernommen wird, müssen wir wieder php artisan migrate
ausführen:
user@rechner /var/www/html/systeme/tasksscratch $ php artisan migrate
Migration table created successfully.
Migrated: 2014_10_12_000000_create_users_table
Migrated: 2014_10_12_100000_create_password_resets_table
Migrated: 2016_08_04_120955_create_tasks_table
user@rechner /var/www/html/systeme/tasksscratch $ php artisan migrate:status
+------+------------------------------------------------+
| Ran? | Migration |
+------+------------------------------------------------+
| Y | 2014_10_12_000000_create_users_table |
| Y | 2014_10_12_100000_create_password_resets_table |
| Y | 2016_08_04_120955_create_tasks_table |
+------+------------------------------------------------+
direktes Anpassen der Datenbank
Jetzt müssen wir noch bestimmte Benutzer zu "Admins" machen:
Für den Anfang gehe ich direkt in die Datenbank und stelle die role_id bei den gewünschten Benutzern um:
php artisan tinker
>>> DB::table('users')->get();
=> [
{#649
+"id": 1,
+"name": "admin",
+"email": "test@test.test",
+"password": "?????????????????????????????????????????????????????????x",
+"remember_token": null,
+"created_at": "2016-08-18 13:12:24",
+"updated_at": "2016-08-18 13:12:24",
+"role_id": 0,
},
]
>>> DB::table('users')->where('name','admin')->update(['role_id'=>1]);
=> 1
>>>
Alternativ: Anpassen der Datenbank mittels Seeds:
Mit Seeds können bestimmte Einträge in eine Datenbank erstellt werden.
Zum Vergleich: Migrationen sind Dateien zum Erstellen der Datenbanktabellen, Seeds sind Dateien um die Datenbank mit bestimmten Werten zu befüllen.
Um einen bereits registrierten Benutzer mit dem Namen "admin" die role_id: 1 zu geben, füge ich folgenden Inhalt in die Datei: database/seeds/DatabaseSeeder.php hinzu:
<?php
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
DB::table('users')->where('name','admin')->update(['role_id'=>1]);
}
}
Im Anschluss werden Seeds mit folgendem Befehl ausgeführt:
php artisan db:seed
Das Beispiel macht aus einem Benutzer mit dem Namen "admin" einen Administrator, indem es das Feld role_id auf 1 stellt.
Anpassen des Service-Provider
Als nächsten Schritt wollen wir nur den Admins erlauben, bestimmte Einträge in der Datenbank zu erstellen. Alle registrierten Benutzer dürfen die Einträge lesen. Dazu passe ich den AuthServiceProvider an und führe eine Abfrage mit "isadmin" ein:
in Providers\AuthServiceProvider.php
public function boot()
{
$this->registerPolicies();
Gate::define('isadmin', function ($user) {
return $user->role_id == "1";
});
}
isadmin kann im Controller und in den Views folgendermaßen verwendet werden:
Verwendung im Controller
use Gate;
if (Gate::allows('isadmin')) {
return view('admin');
}else {
return view('home');
}
Hier nochmal der komplette Inhalt von MyinputController.php
Erstellen, Ändern oder Löschen kann nur von einem Admin-Benutzer (mit aktivierter role_id=1) durchgeführt werden:
<?php
namespace App\Http\Controllers;
use App\Myinput;
use View;
use Illuminate\Http\Request;
use App\Http\Requests;
use Gate;
class MyinputController extends Controller
{
public function __construct()
{
$this->middleware('auth');
}
/**
* Display a listing of the resource.
*/
public function index()
{
// get all the myinputs
$myinputs = Myinput::all();
// load the view and pass the myinputs
return View::make('myinputs.index')
->with('myinputs', $myinputs);
}
/**
* Show the form for creating a new resource.
*/
public function create()
{
// load the create form (app/views/myinputs/create.blade.php)
if (Gate::allows('isadmin')) {
return View::make('myinputs.create');
} else {
return back();
}
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
// validate
$this->validate($request, [
'string' => 'required',
'email' => 'required|email',
'integer' => 'required|numeric']);
// store
if (Gate::allows('isadmin')) {
Myinput::create([
'string' => $request->string,
'email' => $request->email,
'integer' => $request->integer,
]);
}
return back();
}
/**
* Display the specified resource.
*/
public function show($id)
{
// get the myinput
$myinput = Myinput::find($id);
// show the view and pass the myinput to it
return View::make('myinputs.show')
->with('myinput', $myinput);
}
/**
* Show the form for editing the specified resource.
*/
public function edit($id)
{
// get the myinput
$myinput = Myinput::find($id);
// show the edit form and pass the myinput
if (Gate::allows('isadmin')) {
return View::make('myinputs.edit')
->with('myinput', $myinput);
} else {
return back();
}
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, $id)
{
$this->validate($request, [
'string' => 'required',
'email' => 'required|email',
'integer' => 'required|numeric']);
$myinput = Myinput::find($id);
if (Gate::allows('isadmin')) $myinput->update($request->all());
return back();
}
/**
* Remove the specified resource from storage.
*/
public function destroy($id)
{
// delete
$myinput = Myinput::find($id);
if (Gate::allows('isadmin')) $myinput->delete();
// redirect
return back();
}
}
Verwendung in der View
@can('isadmin') canadmin @endcan
Beispiel: index.blade.php
<!-- app/views/myinputs/index.blade.php -->
@extends('layouts.app')
@section('content')
<div class="container">
@can('isadmin')
<nav class="navbar navbar-inverse">
<ul class="nav navbar-nav">
<li><a href="{{ URL::to('myinputs/create') }}">Create a Myinput</a>
</ul>
</nav>
@endcan
<h1>All the Myinputs</h1>
<!-- will be used to show any messages -->
@if (Session::has('message'))
<div class="alert alert-info">{{ Session::get('message') }}</div>
@endif
<table class="table table-striped table-bordered">
<thead>
<tr>
<td>ID</td>
<td>String</td>
<td>Email</td>
<td>Integer</td>
<td>Actions</td>
</tr>
</thead>
<tbody>
@foreach($myinputs as $key => $value)
<tr>
<td>{{ $value->id }}</td>
<td>{{ $value->string }}</td>
<td>{{ $value->email }}</td>
<td>{{ $value->integer }}</td>
<!-- we will also add show, edit, and delete buttons -->
<td>
<!-- show the myinput (uses the show method found at GET /myinputs/{id} -->
<a class="btn btn-small btn-success" href="{{ URL::to('myinputs/' . $value->id) }}">Show this Myinput</a>
<!-- edit this myinput (uses the edit method found at GET /myinputs/{id}/edit -->
@can('isadmin')
<a class="btn btn-small btn-info" href="{{ URL::to('myinputs/' . $value->id . '/edit') }}">Edit this Myinput</a>
<!-- delete the myinput (uses the destroy method DESTROY /myinputs/{id} -->
<form action="./myinputs/{{$value->id }}" onsubmit="return confirm('Are you sure to delete: {{ $value->string}}')" method="POST">
{{ csrf_field() }}
{{ method_field('DELETE') }}
<button type="submit" class="btn btn-danger">
<i class="fa fa-btn fa-trash">Delete</i>
</button>
</form>
@endcan
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
@endsection
meldet sich ein Benutzer (ohne role_id=1) an, kann dieser nur die bereits angelegten Einträge ansehen, die Optionen "Create", "Edit" und "Delete" funktionieren nicht und werden auch nicht angezeigt:
Paket - Laravel Permissions
Für Laravel gibt es fertige Pakete für ein Rechtesystem, z.B. https://github.com/spatie/laravel-permission.
Laravel Permissions arbeitet vom Prinzip mit folgenden Tabellen:
- roles
- permissions
- role_has_permissions
- model_has_roles
- model_has_permissions
Das Paket Laravel Permission deckt hier alle möglichen Szenarien, auch für komplexere Webseiten, ab. So können z.B. Berechtigungen nicht nur auf User, sondern auf beliebige Models gebunden werden.
Als Beispiel wird eine Rolle, hier angelegt mittels Tinker:
Spatie\Permission\Models\Role::create(['name' => 'writer']);
in die Tabelle "roles" geschrieben:
die Berechtigung:
Spatie\Permission\Models\Permission::create(['name' => 'edit articles']);
in die Tabelle "permissions":
die Berechtigung (Permission) kann dann einer Rolle zugewiesen werden:
$permission=Spatie\Permission\Models\Permission::where('name', 'edit articles')->first();
$permission->assignRole("writer")
in der Tabelle "role_has_permissions"
oder direkt einem Benutzer:
App\User::where('name', 'username')->first();
$user->givePermissionTo('edit articles');
Tabelle "model_has_permissions"
Bzw. kann einem Benutzer natürlich eine Rolle zugewiesen werden:
$user->assignRole('writer');
Tabelle "model_has_roles"
Middleware hinzufügen:
app/Http/Kernel.php
:
protected $routeMiddleware = [
// ...
'role' => \Spatie\Permission\Middlewares\RoleMiddleware::class,
'permission' => \Spatie\Permission\Middlewares\PermissionMiddleware::class,
'role_or_permission' => \Spatie\Permission\Middlewares\RoleOrPermissionMiddleware::class,
];
dies kann dann in den Routes verwendet werden:
Route::group(['middleware' => ['role:super-admin','permission:publish articles']], function () {
//
});
oder direkt im Controller
public function __construct()
{
$this->middleware(['role:super-admin','permission:publish articles|edit articles']);
}
Verwendung in routes/web.php
Route::group(['prefix' => '', 'middleware' => 'role:writer'], function()
{
...
Verwenden in Blade-Tempaltes
@role('admin')
<a class="nav-link" href="/admin">Admin</a>
@endrole
{{percentage}} % positiv
DANKE für deine Bewertung!
Fragen / Kommentare
(sortiert nach Bewertung / Datum) [alle Kommentare(neueste zuerst)]