Laravel Mailhog Docker

Letztens wurde ich gefragt, wie ich Mail bei Laravel teste. Ich meinte ich habe einen SMTP Server den ich nutzen kann. Da meinte er, dass wäre zwar okay aber man könnte sich damit auch eine valide Mailadresse verbrennen. Mit verbrennen meint der Kollege, dass sie global als SPAM Mailadresse angerechnet werden kann. Falls die Tests mal ausufern sollten. Hmm. So richtig überzeugt hatte es mich jetzt nicht, aber ich hab mich seiner Empfehlung Mailhog zu nutzen nicht wiedersetzt. Im Gegenteil ich sogar ganz dankbar dafür. Weil wann hätte ich mit dieser Gewohnheit sonst gebrochen.

Mailhog ist ein lokal Dienst. Man kann sich diesen auf den Rechner Installieren. Dieser Dienst kommuniziert über den SMTP Standard Port 1025. Das bedeutet wenn wir unsere Laravel Konfiguration in der .env auf mailhog anpassen, senden wir aus der Applikation an unseren lokalen SMTP Server. Mailhog hat auch ein User Interface mit dem wir die Mails dann anzeigen lassen können.

Der einfachste Weg Mailhog zu nutzen ist über Docker. Dafür müssen wir nur:

docker run -d -p 1025:1025 -p 8025:8025 mailhog/mailhog

eingeben.

In unserer .env Datei passen wir noch die SMTP Konfiguration an:

MAIL_MAILER=smtp
MAIL_HOST=localhost
MAIL_PORT=1025
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS=hello@world.com
MAIL_FROM_NAME="${APP_NAME}"

Dein “Fake” Mailhog EmailClient kannst über localhost:8025 erreichen.

Wenn Du deine gesamte Umgebung über ein docker-compose laufen lässt kannst du natürlich auch den Mailhog SMTP Server mit hinzu fügen.

services:
   mailhog:
     image: mailhog/mailhog:latest
     restart: always
     ports:
       - 1025:1025
       - 8025:8025

Ein gesamte docker-compose Laravel Umgebung findet ihr hier:
https://github.com/MikeLowrey/docker-compose-laravel-2021

. Ansonsten findest Du eine ausführlichere Mailhog Anleitung unter: https://kinsta.com/de/blog/mailhog/.

Laravel Spatie Permission Package – Kurz mal erklärt

Die belgische „SoftwareGang“ Spatie haut ein coole Laravel Package nach dem anderen raus. Super nützlich und sehr angenehm zu nutzen. Heute gibt es einen Einstieg in das Package Spatie Permission Package.

I. Einrichten

1. Schritt:

composer require spatie/laravel-permission 

2. Schritt: Permission Service Provider anmelden

Füge dafür den „PermissionServiceProvider“ in der Datei config/app.php ein.

 'providers' => [
     // ...
     Spatie\Permission\PermissionServiceProvider::class,
 ]; 

3. Schritt: Kopiere die migration aus dem Vendor in das Projektverzeichnis

php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider" 

4. Nun noch den Config cache bereinigen

php artisan config:clear

5. Migration starten

php artisan migrate 

6. Füge den Trait zum User Model hinzu.

 use Spatie\Permission\Traits\HasRoles;

 class User extends Authenticatable
 {
     use HasApiTokens, HasFactory, Notifiable, HasRoles;
 
 

Dadurch haben wir nun Zugriff auf die Spatie Permissions Methoden um dem User Rolen zuzuweisen.

Das war das einrichten und nun gehen wir über zum nutzen.

II. Anwenden

Dafür gehen wir aus, dass wir einen Blog bauen. Hier haben wir unterschiedliche Rollen wie zum Beispiel: Admin, Writer, Reviewer. Der Weiter hat folgende Berechtigung: „edit post“.

Um die Rollen und Berechtigungen zu erstellen, nutzen wir einen Seeder. Den erstellt man in Laravel mit:

php artisan make:seeder RolesSeeder 

In deren run Methode definieren wir unser Model.

 <?php
 namespace Database\Seeders;
 
 
 use Illuminate\Database\Seeder;
 use Spatie\Permission\Models\Role;
 
 
 class RolesSeeder extends Seeder
 {
     /**
      * Run the database seeds.
      *
      * @return void
      */
     public function run()
     {
         $roles = ['admin', 'provider', 'customer'];
 
 
         foreach($roles as $role) {
             Role::create(['name' => $role]);
         }         
     }
 } 

Das Gleiche nun auch für die Berechtigungen:

php artisan make:seeder PermissionsSeeder 
 <?php
 namespace Database\Seeders;
 
 
 use Illuminate\Database\Seeder;
 use Spatie\Permission\Models\Permission;
 
 
 class PermissionsSeeder extends Seeder
 {
     /**
      * Run the database seeds.
      *
      * @return void
      */
     public function run()
     {
         $permissions = ['edit post', 'delete post'];
 
 
         foreach($permissions as $permission) {
             Permission::create(['name' => $permission]);
         }                 
     }
 } 

Jetzt deklarieren wir der DatabaseSeeder Klasse, welche Seeds er „runen“ soll.

<?php
 namespace Database\Seeders;
 
 
 use Illuminate\Database\Seeder;
 
 
 class DatabaseSeeder extends Seeder
 {
     /**
      * Seed the application's database.
      *
      * @return void
      */
     public function run()
     {
         $this->call(RolesSeeder::class);
         $this->call(PermissionsSeeder::class);
 
 
         // create User
         $user = \App\Models\User::create([
             'name' => 'Martin',
             'email' => 'martin@peoplehelper.org',
             'password' => bcrypt('password')
         ]);
 
 
         // asaign user a role as writer
         $user->assignRole('writer');
 
 
         // assign permission to an role (1 = edit post)
         $role = $user->roles[0];
         $role->givePermissionTo(\Spatie\Permission\Models\Permission::find(1));
     }
 } 

Sobald wir das haben können wir mal die Migration durchlaufen lassen:

php artisan db:seed  
// bzw.
php artisan migrate:refresh –seed 

Ein Blick in unsere Datenbank zeigt, dass wir erfolgreich die Role Writer dem User Martin zugewiesen haben.

Für das Wiederrufen einer Berechtigung ($user->revokePermissionTo(‘delete post‘) ) oder das entfernen einer Role vom User ($user->removeRole(‘writer‘)) könnt das ganz gut in der Spatie Doku nachlesen. Das Gleiche gilt für die Konditional Abfragen wie zum Beispiel $user→can(‘delete post‘).

Die „Blade Directives“

Hier kann man mit:

 @can(‘edit post‘)
 ...
 @endcan
 
 
 @role(‘writer‘)
 …
 @endrole
 
 
 @hasrole(‘writer‘)
 ...
 @endhasrole
 
 
 @hasanyrole(Collection || Array )
 @endhasanyrol
 
 
 @hasanyrole(‘writer|admin‘)
 ...
 @endhasanyrole
 
 
 @unlessrole('admin')
 ...
 @end unlessrole 

Logiksecurity statt nur Viewhidding

Ich musste mal mit einem Indischen PHP Entwickler zusammen arbeiten, der die Berechtigungslogiken nur in den Blades abbildete. Im Controller und bzw. oder Serviceklassen hat er es weitestgehend vermieden. Was zu einem Sicherheitsproblem wurde.

Deshalb sein es hier wichtig zu erwähnen, dass nicht zu vergessen. Ein eleganter und einfacher Ansatz wäre hier mit einer Middleware zu arbeiten. Somit kann man die Routes ohne viel Umwege gut vor unberechtigten URL aufrufen schützen.

Alles was wir machen müssen ist:

1: Schritt: Das PermissionRole Package der Route Middleware hinzufügen.

Das passiert in der Kernel.php Datei in der Membervariablen $routeMiddleware. Hier fügen wir dem Array folgende Middlewarepakete hinzu.

protected $routeMiddleware = [
     // ...
     'role' => \Spatie\Permission\Middlewares\RoleMiddleware::class,
     'permission' => \Spatie\Permission\Middlewares\PermissionMiddleware::class,
     'role_or_permission' => \Spatie\Permission\Middlewares\RoleOrPermissionMiddleware::class,
 ]; 

Ab diesem Moment können wir in den Routes über Rollen und Berechtigungen schützen.

 Route::group(['middleware' => ['role:admin']], function () {
     //
 });
 
 // bzw.   
 
 Route::get(‘posts/create‘, [\App\Controllers\PostController,])→ ‘create‘])->middleware(['middleware' => ['role:admin']);
 
 
 Route::group(['middleware' => ['permission:publish articles']], function () {
     //
 });
 
 
 Route::group(['middleware' => ['role:super-admin','permission:publish articles']], function () {
     //
 });
 
 
 Route::group(['middleware' => ['role_or_permission:super-admin|edit articles']], function () {
     //
 });
 
 
 Route::group(['middleware' => ['role_or_permission:publish articles']], function () {
     //
 }); 

Wer die routes aus einem Grund nicht schützen kann oder will, kann das im Controller oder in der ServiceKlasse Deiner Anwendung auch vornehmen. Dort lädt man im Konstruktor der jeweiligen Klasse die Middleware und überprüft dann die Userberechtigung bzw. Userrolle.

 public function __construct()
 {
     $this->middleware(['role:admin','permission:publish articles|edit articles']);  
     // oder
     $this->middleware(['role_or_permission:super-admin|edit articles']);
 } 

Das war es auch schon für den kurzen Einstieg. Viel Spaß beim ausprobieren und nutzen!

Laravel Faker – Kurz mal erklärt

Alle nutzen anscheint Faker. Es gab mal einen ehemaligen US Präsidenten der meinte die Washington Post verbreitet Fake(r) News. Er selbest wiederum hatte sich eine Faker API in sein damals noch nicht gesperrten Twitter Account reinlegen lassen. Fakes sind in der Geschichte der Menschheit immer präsent gewesen und nicht erst seit 2016. Aber zurück zum Tec Stack.

Der Faker ist eine externe Bibliothek des Laravel Werks Package. Mit dem Faker kann man sich Testdaten in die Datenbank schreiben lassen. Testdaten die man benötigt um seine Software zu testeb. Ich selbst erinnere mich zu gut, wie ich in meinen Anfängen als Dev über einen MySQL Client meine Testdaten immer eingehackt habe. Das war einfach müßig. Daher hatte ich bereits kurze Zeit später ein Script dass mir feste Datensätze in die Datenbank importierte. Damals kannte ich Faker noch nicht. Lag auch daran das ich als PHP Entwickler anfing. In anderen Sprachen war das schon ein alter Hut.

Wie geht man vor?

Schritt 1 – Faker Klasse erstellen

Wir wollen unsere User Tabelle in der DB auffüllen. Das machen wir über das Laravel Konsolenprogramm artisan.

php artisan make:factory UserFactory  
// oder
php artisan make:factory UserFactory --model=User 

Schritt 2 – Faker definition schreiben

Die neue Faker Klasse wird in Ihrem Verzeichnis database/factories abgelegt. Mit der Option –model gibt man Artisan mit, mit welchem Model er die neue Fakerklasse assoziieren soll. Somit ist das Model gleich in der Klasse griffbereit, statt es noch mit use App\Models\xxx in die Klasse zu holen. Also am besten immer gleich mit.

Dann tragen wir in dem Array in der Klassenmethode definition() unsere Datenbank Keys ein. Die Values werden mit Faker gesetzt.

public function definition()
{
    return [
        'name' => $this->faker->name,
        'address' => $this->faker->address,
    ];
} 

Für alle möglichen Fakemöglichkeiten schaut mal in das GitHub Repository: https://github.com/fzaninotto/Faker.

Schritt 3 – Landessprache einstellen (Localisation)

Jetzt müssen wir nur noch den Laraval Faker auf Deutsch stellen. Dazu gehen wir in die app.php Datei im Config Ordner. Ihr werdet sehen, dass dirt bereits ein faker local gesetzt ist. Standardmäßig auf en_EN. Das ändern wir in unsere gewünschte Sprache. In meinem Fall jetzt de_DE.

'faker_locale' => 'fr_FR',

Schritt 4 – Testen ob der Faker funktioniert

Nun testen wir, ob der Faker auch wirklich funktioniert. Dazu gehen wir we folgt vor:

 php artisan tinker
 Owner::factory()->count(1)->create() 
Tinker Output
Tinker Output

Und das war es auch schon. In der Testklasse triggerst Du den gewünschten Faker in der SetUp Methode an und verfügst dann in deiner Testdatenbank randomisierte Datensätze. Die nach dem Test automatisch wieder gelöscht werden.

Laravel – Service, Repository Pattern

Ein wichtiger Baustein der Softwareentwicklung ist die Softwarearchitektur. Ab einer bestimmten Größe steht und fällt, meines Erachtens, ein Projekt mit der Softwarearchitektur. Damit ist nicht gemeint, das prozedural geschriebener Code perse schlecht ist. Im Gegenteil. In der Vergangenheit habe ich mit prozedural geschriebenen Code gute Software gebaut die teilweise bis heute läuft. Ich erinnere mich auch zu gerne an meine Zeit bei der Fincaorca GmbH in Berlin und deren CTO Jens. Dieser hat mit einem weiterem Kollegen 2006 ein Reisebuchungsportal aufgesetzt. Ein sehr großer Teil war dort prozedural geschriebener Code. Wo ich 2016 hinzugestoßen bin, war es ein Mix aus objektorientierten geschrieben Modulen und dem alten prozedural geschriebenen Grundgerüst. Und erst vor kurzem (01/2021!) habe ich erfahren, dass es nun mit einem schönen PHP Framework ersetzt werden soll. Lange Rede, kurzer Sinn. Soll nur heißen, dass eine Software Straight Forward und gut durchdacht sein soll. Pragmatische Ansätze bei wichtigen Entscheidungen, machen das Leben als Softwareentwickler aber auch der Auftraggebers um einiges leichter.

Bei Laravel gibt es von Hause aus nicht das Service Repository Pattern. Jetzt werden einige sagen: Momentmal Controller Model ist doch ein wenig wie Service Repository. Ich sage nein. In den meisten Fällen ist ein Request nicht nur „get-all-users“ (gebe mir alle User) zurück. Sobald eine Komplexität die Abfrage einfärbt ist es Zeit, über ein Service Repository Pattern (SRP) nachzudenken. Aus folgenden Gründen: Spätere Wartung, Änderungen oder Erweiterungen werden definitiv mit diesem Pattern leichter gehen und das bei Gleichzeitiger Fehlerreduktion. Was unterm Strich bedeutet: weniger Stress, mehr Zeit für andere Sachen und Kosten gespart.

Wie geht man also vor?

Stellen wir uns vor:
– wir haben ein eShop
– der Nutzer befindet sich in seinem Backend und will den Preis seiner letzten Rechnung einsehen
– über die Order id wird dieser Prozess angetriggert
– wir gehen von einem XHR Request aus
– die Order soll sich selbst aber auch ihre Order Items und Summe des Einkaufs netto und UST mitliefern. Damit wir eine schöne Auflistung unserer Produkte haben.

Der Order Controller bekommt den Request mit einer OrderID rein. Dieser könnte nun in seiner Logik in der selbigen Methode verarbeitet werden.

$order = Order::find($order_id);   // gebe      
$sum_net = $sum_gross = $vat = 0; // Initialisierung der vars
foreach($order->order_items as $orderItem)  // loop durch die einzelnen OrderItems
{
    $orderItem->product; // hole das zugehörige Produkt, welches zum Order Item in Relation steht, ab
    $sum_net += $orderItem->order_item_price * $orderItem->order_item_quantity; // Summe Netto alle Produkte / Items
    $vat += ((($orderItem->order_item_price * $orderItem->order_item_quantity) * $orderItem->vat) / 100); // Steuer insgesamt
}    
         
$order->sums = ["net"=>$sum_net,"vat"=>$vat,"gross"=>($sum_net+$vat) ];
return $order; 

zurück bekommen wir ein JSON Objekt:

{Order: {}, OrderItems: {}, sums: {net: x,vat: x, gross: x} 

Hmm. Kann man machen, aber ist doch irgendwie ein wenig zu viel Business Logik drin, oder? Ein Controller soll doch nur die Anfrage annehmen und eine Antwort geben. Die Logik sollte dann ein Service übergeben werden. Der Service beinhaltet die Business Logik und arbeitet nur diese Logik ab. Der Service arbeitet aber nicht mit den Modelen zusammen. Den die Datenquellen bzw Datenlogik sind beim Repository verankert. Des Repository kennt die Modele und spricht sie entsprechend an.

Also schreiben wir es nun mal um.

Order Controller

use \App\Service\OrderService;  

public function __construct() 
{
    $this->orderService = new OrderService();
}
 
public function order(Request $requerst, int $id)
{
    $order_id = (int) $id;
    return $orderService→getOrder();
}

Order Service

 
use \App\Service\OrderRepository;
 
public function __construct() 
{
    $this-> orderRepository = new OrderRepository();
}
 
public function getOrder(int $order_id) {
    # hier kommen die Business Logiken rein
    #- Validierung der Order ID
    #- check ob Nutzer die Anfrage überhaupt machen darf (AUTH)
    #- …
    #- hole jetzt aus der Repository die Order ab:
    $order = $orderRepository→getOrderById($id);
    $sum_net = $sum_gross = $vat = 0; // Initialisierung der vars
    foreach($order->order_items as $orderItem)  // loop durch die einzelnen OrderItems
    {
        $orderItem->product; // hole das zugehörige Produkt, welches zum Order Item in  Relation steht, ab
        $sum_net += $orderItem->order_item_price * $orderItem->order_item_quantity; // Summe Netto alle Produkte / Items
        $vat += ((($orderItem->order_item_price * $orderItem->order_item_quantity) * $orderItem->vat) / 100); // Steuer insgesamt
     }            
     $order->sums = ["net"=>$sum_net,"vat"=>$vat,"gross"=>($sum_net+$vat) ];
     return $order;
 } 

Order Repository

use \App\Models\Order;
public function getOrderById(int $id) 
{
    return Order::find($id);
} 

Das wäre jetzt ein einfaches Beispiel. Aber wenn man ein ganzes Projekt in dieser Gangart umsetzt, wird man die Vorteile deutlicher zu spüren bekommen. Klassen lassen sich besser lesen und der wichtigste Punkt zum Schluss. Man kann dieses Pattern hervorragen testen.

Laravel Model kurz mal erklärt

Heute mal leichte Kost. Laravel Model. Was ist das und was stellt man damit an, wie erstellt man ein Model und was kann es so alles.

Genug der langen Worte, fangen wir an!

Was ist ein Model?

Dafür blicken wir auf ein DesignPattern der Programmierung und zwar dem MVC Muster. MVC steht für Model, View und Controller.

Im groben kann man sagen, das Model handelt die Business Logik eines MVC basiertem Framwork. In Laravel enthält das Model die logische Struktur (Schema) und die Beziehungen (Relations) der dahinterliegenden Datenressourcen. Bei Laravel hat jede Datenbank Tabelle ein Model mit dem es mit der Anwendung kommuniziert. Also lesen, schreiben, updaten, löschen wird über das Model erst ermöglicht und verwaltet. Du findest seit Laravel 8 die Models unter app/models. Lange Zeit waren die Models im Root von app hinterlegt. Was keiner so richtig verstand, außer Oti (Taylor Otwell).

Wie kann man ein Laravel Model erstellen

Mit dem Kommandozeilen Tool artisan lässt sich bei Laravel so fast alles wichtige erstellen. Leider bis heute noch nicht die Views. Aber mit einem kleinen Workaround geht auch das. Aber zurück zum Thema. Ein Model erstellt ihr mit folgender Bash Zeile:

php artisan create:model <model-name>

Ersetzt <model-name> mit dem Namen den ihr wollt und zwar im Singular. Kleines Beispiel:

php artisan make:model Product -m

Wichtig ist hier anzumekren: dass ihr den Model namen in CamelCase schreibt und Singular bezeichnet sowie der erste Buchstabe groß sein sollte.

Man kann dem Artisan Command noch Parameter mitgeben. Zum Beispiel:

  • -m bzw. –migration (erstellt eine Migartiondatei)
  • -c (erstellt den dazugehörigen Controller. In umserem Fall also ProductController)
  • -r (erstellt eine Ressource. ProductRessource)

Wenn man den make:model Command ausführt erstellt uns Laravel artisan unter app/model/. Unser Model.

namespace App;

use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
    //
}

Ihr könnt Euch mal aus Jucks in eurem vendor Verzeichnis die abgleitete abstrakte Model (Illuminate\Database\Eloquent\Model) Klasse anschauen. Hier wird einem bewusst, welche Vielfältigkeit mn hier einstellen bzw. überschreiben kann. Ihr könnt in eurem Model die Default Werte einfach überschreiben. Kleines Beispiel: Die Membervariable protected $perPage = 15. Wollt ihr eine Pagination mit nur 10 Treffern pro Seite. Schreibt dazu dann protected $perPage = 10; und schon habt ihr den Defaultwert überschrieben.

Wichtige Variablen die ihr eventuell mal anfassen müsst wären:

protected $table = ““; // Euer Datenbantabellennamen

protected $primaryKey = “id“; // Laravel nimmt an, dass jede Tabelle id als Primären Schlüssel verwendet. Falls das nicht so ist könnt ihr dies hier ändern

public $timestamps = false; // Laravel fügt von Haus aus jeder Tabelle noch zwei Spalten (created_at und updated_at) hinzu. Falls ihr das nicht wünscht, überschreibt die public Membervariable $timestamp mit false;

protected $hidden = [ ‘password’, ‘remember_token’]; // wenn Ihr ein Model abfragt werden euch alle Spalten ausgeliefert. Es sein den ihr wollt, dass bestimmte Felder nicht angezeigt werden sollen. Wie zum Beispiel das Passwort bei einer Abfrage nach dem User::find(1);

protected $fillable = [‘name’,’email’,’password’]; // sind Felder die geupdated werden dürfen.

protected $guarded = []; // Ist ein Array mit Spaltennamen des Models die nicht geupdated werden dürfen

JWT in Laravel einrichten – Kurz mal erklärt

Ein sehr großes Topic vor beginn einer neuen Applikation ist die Authentifizierung. Bei der Hypoport AG in Berlin wurde bei einem Projekt ein ganzer Monat mit mehreren Entwicklerteams das Thema Login geplant. In anderen Projekten, die sicher laufen sollen, verhält sich das ähnlich.

Deswegen sollte das Thema von Anfang an immer gut durchdacht sein. Erspart einem eine Menge Zeit und Ärger.

Laravel bietet eine Reihe von Authentifizierung Bibliotheken an. Die Umfänglichste ist Laravel Passport. Eine smart, elegante ist JWT. Genau diese möchte ich heute euch kurz mal vorstellen.

JWT steht für JSON Web Token

Bei der Komminkation zwischen dem Browser und dem Server ist es notwendig den Nutzer eindeutig zu identifizieren. Es geht Sessionbasiert oder wie beim JWT token basiert. Der Ablauf sieht wie folgt aus:

  • Nutzer besucht unserer Website
  • Nutzer logt sich mit seiner Emailadresse und Passwort über das entsprechende Login Formular ein
  • Server überprüft seine Anfragen und bei erfolgreichem Abgleichen gibt der Server dem Browser einen Token zurück.
  • der zurückgelieferte Token wird entweder im LocalStorage oder in einem Cookie gespeichert
  • beim nächsten Request zu Server wird der Token im Header als Bearer mitgeliefert (hier wird gerne der Header Accept vergessen. Der da sein sollte application/json)
  • der Server kann anhand des Token den Nutzer identifizieren und weiß zumindest wem er nun die Antwort schickt

In unserem Beispiel möchten wir mal eine ganz einfache Nutzer Verwaltung erstellen. Der Einfachheitshalber regeln wir das alles ohne Controller sondern direkt im Router (api.php).

1. Wir installieren Laravel

2. Wir installieren JWT Auth mit

composer require tymon/jwt-auth

Wenn Du jwt-auth nicht installieren kannst, weil diese oder eine ähnliche Ausgabe in deiner Console erscheint:

Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - Root composer.json requires tymon/jwt-auth ^0.5.12 -> satisfiable by tymon/jwt-auth[0.5.12].
    - tymon/jwt-auth 0.5.12 requires illuminate/support ~5.0 -> found illuminate/support[v5.0.0, ..., 5.8.x-dev] but it conflicts with another require.


Installation failed, reverting ./composer.json and ./composer.lock to their original content.

Kannst Du es mal mit diesem composer Befehl versuchen. Denn wahrscheinlich gibt es bei Dir ein kleines Versionsproblem.

composer require tymon/jwt-auth --ignore-platform-reqs

3. Wir setzen den JWT Provider mit:

php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"

4. Wir generieren unser JWT Secret Key mit:

php artisan jwt:secret

5. Wir implementieren in unserem User Model die Klasse Tymon\JWTAuth\Contracts\JWTSubject

– use Tymon\JWTAuth\Contracts\JWTSubject

– wir implementieren das Model User mit dem JWTSubject Interface

class User extends Authenticatable implements JWTSubject

– wir fügen die zwei JWTSubject Methoden hinzu:

getJWTIdentifier(): Gibt den JWT Token zurück.

getJWTCustomClaims(): Gibt ein Array, mit benutzerdefinierten Benutzeranforderungen zurück

**
     * Get the identifier that will stored
     *
     * @return mixed
     */
    public function getJWTIdentifier() {
        return $this->getKey();
    }

    /**
     * Return a key value array with containing any custom claims
     *
     * @return array
     */
    public function getJWTCustomClaims() {
        return [];
    } 

6. Wir konfigurieren unser Auth Guard und sagen dem System , dass wir die api Anfragen mit JWT authentifizieren möchten

   'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],

        'api' => [
            'driver' => 'jwt',
            'provider' => 'users',
            'hash' => false,
        ],

Jetzt schreiben wir in unser Routes einige testrouten:

// create a user
Route::post('/create-user', function (Request $request) {
    App\Models\User::create([
        'name' => 'Martin',
        'email' => 'martin@peoplehelper.org',
        'password' => Hash::make('password')
    ]);
    return $request->user();
});
//Route::get('/user-create', [App\Http\Controllers\User::class, 'test'])->name('test');

// login a user
Route::post('/login', function (Request $request) {
    $credentials = $request->only(['email','password']);
    $token = auth()->attempt($credentials);
    return $token;
});

// grab auth user
Route::middleware('auth')->get('/user-profile', function (Request $request) {
    return auth()->user();
});

Laravel config Datei anlegen

Ich musste mal bei einer bestehenden Laravel Installation eine Paypal Integration bei einem Kunden vornehmen. Nebenbei bemerkt möchte ich das mal loswerden. Paypal hat eine schreckliche Dokumentation. Sie ist überhaupt nicht intuitiv. Aber das ist überhaupt ein anderes Thema.

Ich installierte im Projekt über den Composer die Paypal SDK:

composer require paypal/paypal-checkout-sdk 

Zusätzlich legte ich mir einen neuen Order Services unter app. Dort legte ich eine neue Datei names PaypalClient an. Diese beinhaltete die Logik um mit dem Paypal server in Kontakt zu treten um zum Beispiel eine Bestellung und deren Details sich ausgeben zu lassen. Das kann zum Beispiel und ist in meinem Fall auch so, wichtig um den Bestellvorgang in meiner Datenbank zu hinterlegen. Die PaypallClient Klasse benötigt dazu aber Credentials (Client_id, Secret). Diese kann man natürlich direkt aus der .env laden. Aber eleganter wäre es die aus einer eigens benannten config Datei zu holen. Die folgerichtig auch im config Ordner liegt. Wir legen also eine neue Datei unter config an. Und fügen folgenden Code dort ein:

<?php
/**
 * PayPal Setting & API Credentials
 */
return [
    'client_id' => env('PAYPAL_CLIENT_ID', ''),
    'secret' => env('PAYPAL_SECRET', ''),
];

Und in der env fügen diese zwei zeilen ein:

PAYPAL_CLIENT_ID=xxx
PAYPAL_SECRET=yyy

Und an dem Ort wo wir nun die Credentials benötigen – in meinem Fall nun in der PaypalClient Klasse – holen wir uns die Daten mit

$client_id = config('paypal.client_id');
$secret = config('paypal.secret');

Das wirkt jedenfalls aufgeräumter und hat Potenzial bei zukünftigen Herausforderungen mit dem Kunden flexibler zu arbeiten. Zum Beispiel könnt ihr ja in der paypal.php Config Datei einen automatischen switch zwischen Production und Development Umgebung vornehmen.

SeoTheater Autoren