RESTful Authentication mit Rails 2.0 Tutorial

16. März 2008 von Sven Kubiak

Seit dem Ruby on Rails 2.0 im Dezember 2007 erschienen ist, hört man in diesem Zusammenhang immer wieder ein Schlagwort: RESTful. Einer der populärsten Erweiterungen für die Authentifizierung ist das Restful Authentication Plugin von Rick Olson, dass auf “acts as authenticated” basiert. Das Plugin bringt genau das mit, was man sich unter einer vollwertigem Registrierung und Authentifizierung vorstellt: Registrierung mit oder ohne Aktivierung sowie An- und Abmeldung mit Cookie oder ohne. Wie man das Plugin einrichtet und konfiguriert, möchte ich in diesem Tutorial erläutern. Vorweg muss ich allerdings anmerken, dass der Großteil dieses Tutorials nicht auf meinem Mist gewachsen ist, sondern auf einem einem Blogeintrag von Ekerete Akpan basiert. Ich hab seinen Beitrag ins deutsche Übersetzt und einige Erweiterungen hinzugefügt. Da ich derzeit intensiv an einer Benutzer-Authentifizierung arbeite, werde ich das Tutorial sukzessive erweitern.

Voraussetzungen
Für die weitere Vorgehensweise wird vorausgesetzt, dass Rails 2.0 installiert ist, ein Projekt vorhanden ist, und das in der Datenbank keine Tabelle “Users” existiert.

Installation
Zunächst muss das Plugin installiert werden. Dafür öffnen wir die Konsolse und wechseln in unser Projekt. Mit dem folgenden Befehl wird das Plugin installiert:

ruby script/plugin install http://svn.techno-weenie.net/projects/plugins/restful_authentication/

Generator
Das Plugin bringt einen eigenen Generator mit, welcher den Controller, das Model, die Views und einen Observer erstellt. Darüberhinaus passt der Generator auch die routes.rb an, und fügt entsprechende Einträge für den User und Session Controller ein. Der Session Controller kümmert sich um die An- und Abmeldung, während der User Controller die Registrierung übernimmt. Zwei Generatoren stehen zur Auswahl.

Wollen wir einen Registrierung ohne Aktiverung nutzen ist folgender Befehl zu verwenden:

ruby script/generate authenticated user sessions

Für eine Registreriung mit Aktivierung verwenden wir folgenden Befehl:

ruby script/generate authenticated user sessions --include-activation

Migration
Als nächstes müssen wir die Datenbank mit der nötigen Tabelle für die Benutzer füttern. Dafür führen wir eine Migration durch:

rake db:migrate

Ändern der Routes
Damit alle Actions im richtigen Controller landen, müssen wir als nächstes die Routes anpassen. Wir öffnen die Datei config/routes.rb und fügen unsere benötigten Routes ein:

map.activate '/activate/:activation_code', :controller => 'users', :action => 'activate'
map.signup '/signup', :controller => 'users', :action => 'new'
map.login '/login', :controller => 'sessions', :action => 'new'
map.logout '/logout', :controller => 'sessions', :action => 'destroy'

Hier sieht man, dass für eine Actions, die bereits vorhandenen Controller Users und Sessions wiederverwendet werden. Natürlich hätte man hier auch eigene Controller definieren können.

Observer
Für die E-Mail Aktivierung benötigen wir noch einen Observer. Dafür öffnen wir die config/enviroment.rb und fügen innerhalb des Rails::Initializer.run Block den folgenden Observer ein:

config.active_record.observers = :user_observer

E-Mail Versand konfigurieren
Vor Rails 2.0 konnte man eigene Konfigurationen (z.B. für den E-Mail Versand) direkt in die Datei config/environment.rb einfügen. Mit Rails 2.0 gibt es dafür das Verzeichnis config/initializers, in dem Konfigurationsabschnitte abgelegt werden können. Diese werden dann beim Laden eines Plugins automatisch initialisiert. Dies machen wir uns für die E-Mail Konfiguration zu nutzen. Wir erstellen die Datei mail.rb (kann auch jeden anderen Name haben) mit dem folgenden Inhalt:

ActionMailer::Base.delivery_method = :smtp
ActionMailer::Base.smtp_settings = {
    :address => "smtp.domin.de",
    :port => 25,
    :domain => "www.domain.de",
    :authentication => :login,
    :user_name => "benutzername",
    :password => "passwort"
}

Die Einstellungen sind wie folgt definiert:
Address: Adresse des SMTP-Servers.
Port: Port des SMTP-Server (i.d.R. 25)
Domain: Domainame mit dem sich Rails authentifiziert
Authentication: Authentifizierungsmethode am SMTP-Server (i.d.R. ‘login’)
User_name: Benutzername des SMTP-Benutzers
Passwort: Passwort des SMTP-Benutzers

Möchte man nicht SMTP, sondern z.B. Sendmail nutzen, reicht die folgende Befehlszeile:

ActionMailer::Base.delivery_method = :sendmail

E-Mail Parameter
Für die abschießende Konfiguration müssen wir noch einige Parameter anpassen. Wir öffnen die Datei config/environments/development.rb und fügen die folgende Zeile ein, bzw. passen diese an:

SITE_URL = "localhost:3000"

In der Datei config/environments/production.rb ändern wir diese Zeile wie folgt

SITE_URL = "server.de"

Anschließend öffnen wir die Datei app/models/user_mailer.rb und ändern dort folgende Einträge wie folgt ab:

@body[:url]  = "http://#{SITE_URL}/activate/#{user.activation_code}"
@body[:url]  = "http://#{SITE_URL}/"

Mit dieser Konfiguration läuft die Registrierung sowohl in der Production, als auch in der Develoment Umgebung. Den Parameter SITE_URL muss man natürlich seinen Gegebenheiten entsprechend anpassen. Die eigentliche Konfiguration ist damit abgeschlossen.

Möchte man Änderungen an den beiden E-Mail Templates durchführen, findet man die Vorgaben in der Datei app/views/user_mailer/activation.html.erb und app/views/user_mailer/signup_notification.html.erb.

Nach der durchgeführten Installation und Konfiguration sollte man auf jeden Fall den Webserver neu starten.

Nach der Installation
Wie geht uns nun weiter? Nach der Installation steht uns unter http://localhost:3000/signup die Registrierung zur Verfügung. Unter http://localhost:3000/login kann sich der registrierte Benutzer anmelden. Mit dem Aufruf von http://localhost:3000/logout meldet sich der Benutzer ab.

Arbeiten mit Authentifizierung
Damit uns die Authentifizierung in unserer gesamten Anwendung zur Verfügung steht, nehmen wir aus der Datei controllers/sessions_controller.rb die Zeile:

include AuthenticatedSystem

und fügen sie in die Datei controllers/application.rb ein. In der Datei controllers/users_controller.rb können wir anschließend den Eintrag ebenfalls entfernen. Damit stehen uns alle Funktionen des Plugins in unserer kompletten Anwendung zur Verfügung. Darin enthalten ist u.a. die Funktion logged_in?, mit der wir prüfen können, ob ein Benutzer eingeloggt ist. So könnte z.B. der Login-Dialog wie folgt aussehen:

<h3>Welcome user</h3>
< % if logged_in? %>
<p>Hallo, < %= self.current_user.login %></p>
< % else %>
<!-- login form -->
< % end %>

Authentifizierung
Der Sinn eines solchen Systems ist ja, bestimmten Content nur authentifizierten Benutzern zugänglich zu machen. Deshalb müssen wir unsere Controller mit entsprechenden Aufrufen ausstatten, so dass sie auch nur angemeldete Benutzer “rein” lassen. Hierfür können wir sog. before_filter benutzten. Wollen wir einen bestimmten Bereich unserer Anwendung schützen, fügen wir einfach den Aufruf

before_filter :login_required

in den Controller ein. Ruft ein nicht angemeldeter Benutzer nun die entsprechende Seite auf, wird er automatisch auf die Login-Seite weitergeleitet.

In einigen Situationen kann es vorkommen, dass nicht alle Actions eines Controllers eine Authentifizierung benötigen. Möchten wir nur bestimmte Actions schützen, können wir diese ebenfalls im before_filter angeben:

before_filter :login_required, :only => [ :edit, :update ]

In diesem Beispiel benötigen nur die Actions edit und update eine Authentifizierung. Alle anderen Actions können ohne Anmeldung aufgerufen werden.

19 Kommentare

  1. Michi sagt:

    Hi,

    funktioniert super nach der Beschreibung.
    Vielen Dank fürs Übersetzen und erweitern!

    Gruss Michi

  2. Andi sagt:

    Super Anleitung!

    Nur wie kann ich mir Sessioninfos jetzt merken? Mit meiner alten Methode konnte ich mir in session[:user] zB den Namen merken, jetzt liefert mir vergleichbarer Code in sessions_controller.rb Fehler :-( (.

    Gruß, Andi

  3. Andi sagt:

    Na guuut ;-) ,

    Nach dem Kommentar ist mir der K(l)ick gekommen: self.current_user.login ua funktioniert in allen Sichten (views).

    Andi

  4. Falls sonst noch jemand probleme mit dem activate/9as8dfjasjdf9jasdffj9838d
    hat, nach dem signup:

    fügt das
    user.reload
    in euren user_mailer.rb ein:

    protected
    def setup_email(user)
    user.reload
    @recipients = “#{user.email}”
    @from = “Marketplace”
    @subject = “Activation User Account ”
    @sent_on = Time.now
    @body[:user] = user
    end

    sonst wird irgendein token verschickt, aber sicher nicht der richtige, der richtige wird nämlich mit dem salt versehen, so wie ich’s begreiff.

    Gruss

    Rafael

  5. rick sagt:

    eine frage: brauche ich zum ausprobieren einen rails-server? oder kann ich zb einen beliebigen anderen mailserver einer meiner anderen domains eintragen und den rest normal erstmal von localhost kommen lassen?
    habe in der mail.rb einfach ein konto eines meiner server eingetragen. dann signup versucht, aber keine mail erhalten…

  6. kubi sagt:

    @rick
    Einen Rails-Server brauchst du, damit die Applikation selber läuft. Dieser kann natürlich auch lokal installiert sein. Ob du einen SMTP-Server oder Sendmail oder was auch immer für den Mail-Versand dabei benutzt ist egal.

  7. MM2410 sagt:

    Kann mir mal jemand weiterhelfen. Ich erreiche die Source (http://svn.techno-weenie.net/projects/plugins/restful_authentication/) nicht. Kann ich das Plugin auch über einen anderen Weg bekommen?

  8. kubi sagt:

    @MM2410
    Also bei mir funktioniert der Zugriff auf das SVN.

  9. valley sagt:

    Hallo,

    ich bin soeben daran, eine Registrierungsseite für ein Projekt aufzubauen. Nun habe ich da schon eine Tabelle “Users”, die Angaben zum Benutzer (eMail, Geschlecht, Land, etc.) speichert.
    Wenn ich nun auf dieses Plugin umschwenken möchte, wie kann ich mit diesem die erwähnten zusätzl. Angaben bei der Registrierung ebenfalls aufnehmen und in der DB abspeichern ?
    Sorry, ich bin noch rel. neu mit Rails unterwegs.
    Vielen Dank für die Antwort.
    valley

  10. hendrik sagt:

    vielen dank für die anleitung!
    hab sie jetzt schon für mehrere projekte benutzt. immer wieder gut, um auch keinen schritt zu vergessen!
    weiter so!

  11. Johann sagt:

    Hallo,
    auch von mir ein großes Thanks für das tolle Tutorial.
    Aber die Frage, die ich mir grad stelle ist, wie man damit ein System für zwei oder mehr ganz unterschiedliche Benutzer-Kategorien aufbaut.
    Als Beispiel sei mal eine Anwendung genannt, in der es einen Bereich für Schüler, einen für Lehrer und einen für Administratoren gibt, wobei alle drei UserTypen ganz unterschiedliche Eigenschaften haben und deshalb auch am besten in unterschiedlichen Tabellen bzw. Klassen gespeichert werden sollten.
    Hat da jemand eine Idee? Sorry für die vielleicht banale Frage, aber ich bin noch ganz, ganz neu im Thema Rails…
    Für Tipps wäre ich sehr dankbar!!!
    Vielen Dank Euch im Voraus!

  12. pino sagt:

    @Johann: Versuchs mal mit rolerequirement. Zu finden hier
    http://code.google.com/p/rolerequirement/
    oder hier
    http://github.com/timcharper/role_requirement/tree/master.

  13. helmeloh sagt:

    Danke Rafael,
    Das fehlende user.reload hatte mir auch ein bischen zuviel “salt” in die Aktivierung gestreut. (;-)

  14. Marco sagt:

    Hallo miteinander,

    weiß jemand wo ich die Fehlertexte von englisch auf deutsch übersetzen kann?

    Danke und Grüße,

    Marco

  15. Joern sagt:

    wie sieht ActionMailer.Base mit sendmail aus?

  16. Philipp sagt:

    Besten Dank für dieses kurze und sehr verständliche Tutorial! Funktioniert hervorragend. :)

  17. Rike sagt:

    Hallo, erstmal danke für das super Tutorial. Kann mir jemand sagen wie ich nachvollziehen kann wer sich wann eingeloggt hat? Und gibt es vielleicht ein Möglichkeit eine Kennung nach z.B. 3 Fehlversuchen zu sperren?

    Danke schon mal
    Rike

  18. droom sagt:

    mir scheint, dass der svn auf technoweenie nicht (mehr) funktioniert, und soweit ich sehen konnte ist restful_authentication jetzt auf github vertreten – habe mit

    ruby script/plugin install http://github.com/technoweenie/restful-authentication.git

    ausgecheckt, funktionierte einwandfrei.

Hinterlasse einen Kommentar