Darstellung
Navigation
Mobiles Menü
Darstellung
Navigation
Mobiles Menü
Benutzer-Login mit bcrypt und dem b4um Generator

Benutzer-Login mit bcrypt und dem b4um Generator

In diesem Revisit schauen wir uns die Benutzer-Authentifizierung mit bcrypt noch einmal an – diesmal mit der aktuellen Version 0.4.2 des b4um Generators.
Seit unserem ursprünglichen Tutorial hat sich einiges verändert. Der Generator übernimmt inzwischen deutlich mehr Arbeit: Er erkennt password_digest, richtet has_secure_password ein, berücksichtigt Passwortfelder in Formularen und Tests und kann anschließend eine vollständige Session-basierte Authentifizierung erzeugen.
Wir erstellen einen Benutzer mit Name, E-Mail-Adresse und Passwort, richten Login und Logout ein und schützen anschließend Bereiche unserer Anwendung vor nicht angemeldeten Benutzern.

Voraussetzungen

Wir verwenden eine Rails-Anwendung, in der der b4um Generator installiert ist.
In der Gemfile befindet sich:
gem "b4um_generators", "~> 0.4.2"
Danach installieren wir die Abhängigkeiten:
bundle install
Falls der b4um Generator in diesem Projekt noch nicht eingerichtet wurde, starten wir zunächst den Installations-Wizard:
bin/rails generate b4um:install
Während der Installation fragt uns der Generator unter anderem, ob bcrypt verwendet werden soll.
Hier wählen wir:
Install bcrypt authentication support? (y/n)
y
Damit steht bcrypt für unsere spätere Benutzer-Authentifizierung zur Verfügung.
Installation mit bcrypt

Benutzer erstellen

Als Nächstes benötigen wir ein Benutzer-Modell.
Unser Benutzer erhält einen Namen, eine E-Mail-Adresse und einen password_digest.
bin/rails generate b4um:scaffold User \
  name:string \
  email:string \
  password_digest:string \
  --required=name,email
Mit:
--required=name,email
legen wir gleichzeitig fest, dass Name und E-Mail-Adresse Pflichtfelder sind.
Anschließend führen wir die erzeugte Migration aus:
bin/rails db:migrate
Der entscheidende Punkt ist dabei password_digest.

Wir erzeugen keine Datenbankfelder namens password oder password_confirmation. bcrypt speichert das eingegebene Passwort nicht im Klartext. In der Datenbank befindet sich lediglich der daraus erzeugte Passwort-Hash in password_digest.
password und password_confirmation werden später über has_secure_password bereitgestellt.


Was hat der Generator im User-Modell erzeugt?

Öffnen wir:
app/models/user.rb
Der Generator erkennt das Feld password_digest und richtet die bcrypt-Unterstützung für das Modell ein.
Ein wichtiger Bestandteil ist:
has_secure_password
Außerdem haben wir über --required=name,email unsere Pflichtfelder definiert.
Entsprechend enthält das Modell unter anderem Validierungen für diese Attribute.
has_secure_password stellt uns unter anderem die virtuellen Attribute
password
password_confirmation
zur Verfügung.
Diese müssen nicht als Spalten in der Datenbank existieren.
Das eingegebene Passwort wird von bcrypt verarbeitet und als Hash in password_digest gespeichert.
User-Modell in VS Code

Das Benutzerformular

Auch das Formular berücksichtigt die Passwort-Authentifizierung.
Öffnen wir:
app/views/users/_form.html.erb
Dort finden wir die entsprechenden Passwortfelder.
Für den Benutzer sieht das später wie eine normale Passwort-Eingabe aus. Intern landet das Passwort jedoch nicht direkt in unserem User-Datensatz.

Damit können wir bereits einen Benutzer erstellen.
Wir legen für das Tutorial einen Testbenutzer an.
Beispielsweise:
Name: Max Mustermann
E-Mail: max@example.com
Passwort: ********
Passwortbestätigung: ********
Nach dem Speichern existiert unser erster Benutzer – aber wir haben noch keine eigentliche Anmeldung.
Genau darum kümmert sich der Authentication-Generator.

Authentication erzeugen

Jetzt kommt der zentrale Schritt dieses Revisits.
Wir führen aus:
bin/rails generate b4um:authentication User
Damit weiß der Generator, dass User unser Authentifizierungsmodell ist.
Der Authentication-Generator richtet die benötigte Session-Authentifizierung ein.
Dazu gehören unter anderem:
  • Login und Logout
  • Session-Verwaltung
  • current_user
  • logged_in?
  • require_login
  • die entsprechenden Routen
  • Login-Formular und Session-Controller
  • Anpassungen für die generierten Tests
Authentication-Generator

Wie funktioniert die Anmeldung?

Die Authentifizierung basiert auf einer Rails-Session.
Nach erfolgreicher Anmeldung wird die ID des Benutzers in der Session gespeichert.
Sinngemäß:
session[:user_id] = user.id
Dadurch muss Rails nicht bei jedem Seitenaufruf erneut nach E-Mail-Adresse und Passwort fragen.
Im ApplicationController stellt uns der Generator die benötigten Helfermethoden zur Verfügung.
Öffnen wir:
app/controllers/application_controller.rb
Dort finden wir unter anderem:
helper_method :current_user, :logged_in?
sowie die Methoden:
current_user
logged_in?
require_login
current_user ermittelt den momentan angemeldeten Benutzer anhand der Session.
logged_in? beantwortet die Frage, ob aktuell ein Benutzer angemeldet ist.
Und require_login können wir verwenden, wenn bestimmte Bereiche nur für angemeldete Benutzer erreichbar sein sollen.
Authentication im ApplicationController

Das Login-Formular

Jetzt können wir unsere Login-Seite öffnen.
Die entsprechende Route lautet:
/login
Hier geben wir die E-Mail-Adresse und das Passwort unseres zuvor angelegten Benutzers ein.

Nach erfolgreicher Anmeldung wird die Session gesetzt und der Benutzer zur Anwendung weitergeleitet.
Die Navigation kann jetzt abhängig vom Login-Status unterschiedliche Elemente darstellen.
Beispielsweise können für einen nicht angemeldeten Benutzer Registrierungs- und Login-Möglichkeiten angezeigt werden, während ein angemeldeter Benutzer Zugriff auf sein Profil und den Logout erhält.
Anwendung nach dem Login

Logout

Zur vollständigen Authentifizierung gehört natürlich auch das Abmelden.
Beim Logout wird die Benutzer-ID aus der Session entfernt.
Danach gilt wieder:
logged_in?
# => false
und:
current_user
# => nil
Der Benutzer muss sich erneut mit seiner E-Mail-Adresse und seinem Passwort anmelden, um wieder auf geschützte Bereiche zugreifen zu können.
Navigation nach Logout

Bereiche vor Gästen schützen

Bis jetzt haben wir Authentication eingerichtet, aber möglicherweise dürfen nicht angemeldete Besucher weiterhin Controller-Aktionen aufrufen.
Dafür besitzt der Authentication-Generator die Option:
--protect
Nehmen wir beispielsweise an, unsere Anwendung besitzt einen ProductsController.
Dann können wir Authentication erneut mit einem geschützten Controller aufrufen:
bin/rails generate b4um:authentication User --protect=products
Der Generator ergänzt im ProductsController den entsprechenden Schutz.
Dabei bleiben beispielsweise öffentliche Ansichten wie index und show erreichbar, während Aktionen zum Erstellen, Bearbeiten oder Löschen eine Anmeldung verlangen.
Das Prinzip dahinter ist:
before_action :require_login, except: [:index, :show]
Ein Besucher kann damit weiterhin die Produktübersicht und einzelne Produkte ansehen.
Versucht er jedoch beispielsweise die Seite zum Erstellen eines neuen Produkts aufzurufen, wird er zur Anmeldung weitergeleitet.

Was übernimmt der b4um Generator heute für uns?

Genau hier liegt der wesentliche Unterschied zum älteren Authentication-Tutorial.
Wir müssen die einzelnen Bestandteile nicht mehr manuell zusammensetzen.
Der Scaffold- und Authentication-Generator arbeiten miteinander zusammen.
Bei einem Benutzer mit:
password_digest:string
wird die bcrypt-basierte Passwortverwaltung berücksichtigt.
Der Authentication-Generator ergänzt anschließend die Session-basierte Anmeldung und die benötigten Helfermethoden.
Mit --protect können wir darüber hinaus festlegen, welche Bereiche unserer Anwendung eine Anmeldung voraussetzen.
Dadurch besteht die Authentifizierung nicht aus einer Sammlung einzelner Code-Snippets, die wir selbst miteinander verbinden müssen. Die Generatoren erzeugen eine zusammenhängende Grundlage, die wir anschließend an unsere Anwendung anpassen können.

Sicherheit: Das Passwort wird nicht gespeichert

Ein besonders wichtiger Punkt ist die Passwortspeicherung.
Wenn ein Benutzer beispielsweise folgendes Passwort eingibt:
MeinGeheimesPasswort
landet dieser Text nicht in der Datenbank.
bcrypt erzeugt daraus einen Passwort-Hash, der in:
password_digest
gespeichert wird.
Beim späteren Login wird das eingegebene Passwort gegen diesen Hash geprüft.
Damit kann unsere Anwendung einen Benutzer authentifizieren, ohne dessen ursprüngliches Passwort speichern zu müssen.


Fazit

Mit bcrypt und dem b4um Generator 0.4.2 können wir eine vollständige Grundlage für die Benutzer-Authentifizierung unserer Rails-Anwendung erzeugen.

Der Scaffold-Generator berücksichtigt password_digest und richtet die notwendigen Bestandteile für has_secure_password ein. Der Authentication-Generator ergänzt anschließend Login, Logout, Sessions und die Helfermethoden für den aktuellen Benutzer.

Über --protect lassen sich außerdem Bereiche unserer Anwendung gezielt auf angemeldete Benutzer beschränken.

Damit haben wir gleichzeitig die Grundlage für den nächsten Schritt geschaffen.

Denn bisher unterscheiden wir lediglich zwischen:

nicht angemeldet und angemeldet.

In vielen Anwendungen benötigen wir zusätzlich Benutzer mit erweiterten Rechten.

Genau darum geht es im nächsten Tutorial:

Administratorverwaltung mit dem b4um Generator

Dort erweitern wir unsere bestehende Authentication um Administratoren, schützen den Adminbereich und verwalten Benutzer direkt über eine generierte Admin-Oberfläche.



Meld dich an und schreibe ein Kommentar