Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
Geleitwort des Fachgutachters
Einleitung
1 Einführung
2 Installation
3 Erste Schritte
4 Einführung in Ruby
5 Eine einfache Bookmarkverwaltung
6 Test-Driven Development
7 Rails-Projekte erstellen
8 Templatesystem mit ActionView
9 Steuerzentrale mit ActionController
10 Datenbankzugriff mit ActiveRecord
11 E-Mails verwalten mit ActionMailer
12 Nützliche Helfer mit ActiveSupport
13 Ajax on Rails
14 RESTful Rails und Webservices
15 Rails mit Plug-ins erweitern
16 Performancesteigerung
17 Sicherheit
18 Veröffentlichen einer Rails-Applikation auf einem Server
Ihre Meinung?

Spacer
 <<   zurück
Ruby on Rails 2 von Hussein Morsy, Tanja Otto
Das Entwickler-Handbuch
Buch: Ruby on Rails 2

Ruby on Rails 2
geb., mit DVD
699 S., 39,90 Euro
Rheinwerk Computing
ISBN 978-3-89842-779-1
Online bestellenPrint-Version jetzt bestellen
* versandkostenfrei in (D) und (A)
Pfeil 5 Eine einfache Bookmarkverwaltung
  Pfeil 5.1 Rails-Projekt erstellen
  Pfeil 5.2 Weitere Views anlegen
  Pfeil 5.3 Layout
  Pfeil 5.4 Model
  Pfeil 5.5 CRUD - Create - Read - Update - Delete
  Pfeil 5.6 Fehlerbehandlung in Formularen
  Pfeil 5.7 Flash-Messages
  Pfeil 5.8 Refaktorisierung mit Helper und Partials
  Pfeil 5.9 Authentifizierung
  Pfeil 5.10 Routing
  Pfeil 5.11 RESTful Rails
  Pfeil 5.12 Darstellungsformate in RESTful Rails
  Pfeil 5.13 Ajax


Rheinwerk Computing - Zum Seitenanfang

5.9 Authentifizierung  topZur vorigen Überschrift

Wir haben jetzt eine kleine fertige Applikation, mit der wir Bookmarks verwalten können. Würden wir die Seite veröffentlichen, könnte jeder nicht nur die Liste der Bookmarks sehen, sondern auch Einträge hinzufügen, ändern oder sogar löschen. Da wir das nicht möchten, müssen wir einen Authentifizierungsmechanismus hinzufügen.

Wir müssen also einen Log-in-Bereich schaffen, und erst nach erfolgreichem Log-in darf man Einträge ändern, löschen oder neue Einträge hinzufügen. Die Liste aller angelegten Bookmarks und die Detailseite zu einem Bookmark soll aber für alle sichtbar sein.

Eigenes Authentifizierungs- system

Für die Lösung dieses Problems könnten wir eine HTTP-Authentifizierung wie in Kapitel 3 gezeigt einsetzen oder ein fertiges Plug-in (siehe Kapitel 15), mit dem man sogar mehrere User verwalten kann. Wir wollen hier eine sehr einfache Lösung vorstellen, die ohne Plug-ins auskommt, damit Sie die Möglichkeit haben zu verstehen, was passiert.

Zunächst überlegen wir, welche Auswirkungen ein Authentifizierungssystem auf unsere Index-Seite hat. Wenn ein User die Seite aufruft, der nicht angemeldet ist, soll nur der Link zur Detailseite sichtbar sein. Die Links zum Ändern, Löschen und zur Neuanlage eines Favoriten werden nur angezeigt, wenn ein angemeldeter User die Seite aufruft.

Das bedeutet, der View index.html.erb muss vor der Anzeige der Links abfragen, ob der aktuelle User angemeldet ist oder nicht.

Angenommen, wir hätten eine Methode admin?, die true zurückliefert, wenn ein User angemeldet ist, und false, wenn nicht. Dann könnten wir in der index.html.erb den Link zum Neuanlegen eines Favoriten nur dann anzeigen, wenn die Methode admin? den Wert true zurückliefert:

Listing  app/views/bookmarks/index.html.erb

...
<% if admin? %>
  <p>
  <%= link_to "Neuen Favorit erstellen", :action => "new" %>
  </p>
<% end %>

Das Gleiche gilt für die Links zum Ändern und Löschen, die wir in das Partial _bookmark.html.erb ausgelagert haben:

Listing  app/views/bookmarks/_bookmark.html.erb

<li>
  <%= link_to h(bookmark.title), h(bookmark.url) %>
    (<%= link_to "Details", :action => "show",
    :id => bookmark.id %>
    <%if admin? %>
      |<%= link_to "ändern", :action => "edit",
      :id => bookmark.id %> |
      <%= link_to "löschen", {:action => "destroy",
      :id => bookmark.id},
      :confirm => "Wollen Sie diesen Datensatz wirklich
		  löschen?" %>
    <%end %> )
</li>

Methode admin? anlegen

Bevor wir das testen können, müssen wir die Methode admin? anlegen. Da wir die Methode in den Views des Bookmarks-Controller nutzen, können wir sie als Helper in der Datei app/helpers/bookmarks_helper.rb anlegen. Die Abfrage, ob ein User angemeldet ist oder nicht, ist aber etwas Allgemeingültiges, das wir auch in Views anderer Controller nutzen könnten. Deshalb definieren wir die Methode als Application-Helper in der Datei app/helpers/application_helper.rb:

Listing  app/helpers/application_helper.rb

module ApplicationHelper
  def german_time(time)
    time.strftime("%d.%m.%Y %H:%M")
  end
  def admin?
    false
  end
end

Um die Funktionalität der Abfragen, die wir in die Views gesetzt haben, testen zu können, setzen wir den Rückgabewert der Methode erst einmal auf false und rufen die Index-Seite im Browser auf:

Abbildung  admin? == false

Wenn wir den Rückgabewert der Methode admin? auf true setzen, werden die vorher ausgeblendeten Links angezeigt:

Abbildung  admin? == true

Session

Das heißt, das System funktioniert. Jetzt müssen wir noch dafür sorgen, dass der Rückgabewert der Methode admin? in Abhängigkeit von einem Log-in gesetzt wird. Dazu werden wir über einen neuen Controller eine Session-Variable setzen und in der Methode admin? abfragen, ob sie gesetzt ist. Wenn sie gesetzt ist, liefert die Methode admin? true zurück:

def admin?
  session[:admin] == true
end

Der neue Controller, der für die Authentifizierung und damit für das Setzen der Session-Variablen zuständig ist, heißt authentication und hat den View login.html.erb:

ruby script/generate controller authentication login
exists  app/controllers/
exists  app/helpers/
create  app/views/authentication
exists  test/functional/
create  app/controllers/authentication_controller.rb
create  test/functional/authentication_controller_test.rb
create  app/helpers/authentication_helper.rb
create  app/views/authentication/login.html.erb

form_tag

Neben Test- und Helper-Dateien wurden die Controller-Datei authentication_controller.rb mit der Action login und dem dazugehörigen View login.html.erb erstellt. Im View legen wir das Log-in-Formular an. Da dieses Formular nicht auf einem Model basiert, können wir nicht den Helper form_for benutzen, sondern wir verwenden den Helper form_tag zur Erstellung eines modelunabhängigen Formulars. Zur Erstellung der einzelnen Formularfelder stehen die Helper text_field_tag und password_field_tag zur Verfügung. Das Formular schicken wir an den Authentication-Controller und die Action check, die wir noch im Controller anlegen müssen:

Listing  app/views/authentication/login.html.erb

<h2>Login</h2>

<% form_tag :controller => "authentication",
:action => "check" do %>

  <p>
    <label for="user" >Benutzername</label>
    <%= text_field_tag :user %>
  </p>

  <p>
    <label for="password" >Passwort</label>
    <%= password_field_tag :password %>
  </p>

  <p>
    <%= submit_tag "login"%>
  </p>
<% end %>

Das Formular können Sie über den Aufruf der URL

http://localhost:3000/authentication/login

testen:

Abbildung  http://localhost:3000/authentication/login

Formular- verarbeitung

Abschicken können Sie das Formular noch nicht, da im Authentication-Controller die Action check, an die das Formular geschickt wird, noch fehlt. Die Action check gestalten wir recht einfach, indem wir die beiden Parameter user und password auf feste Werte abfragen. Sind die Werte korrekt, wird die Session-Variable gesetzt, eine Flash-Message ausgegeben, dass die Anmeldung erfolgreich war, und es wird auf die Index-Seite der Bookmarkverwaltung weitergeleitet. Ist die Anmeldung nicht erfolgreich, wird sicherheitshalber die Session gelöscht, eine Flash-Message ausgegeben, dass die Anmeldung nicht erfolgreich war, und es wird wieder das Log-in-Formular aufgerufen:

Listing  app/controllers/authentication_controller.rb

class AuthenticationController < ApplicationController

  def login
  end

  def check
    if params[:user] == "ich" && params[:password] == "geheim"
      session[:admin] = true
      flash[:notice] = "Erfolgreich angemeldet"
      redirect_to :controller => "bookmarks",
      :action => "index"
    else
      reset_session
      flash[:notice] = "Fehler bei der Anmeldung"
      redirect_to :controller => "authentication",
      :action => "login"
    end
  end
end

Wenn Sie das Formular mit dem Benutzernamen »ich« und dem Passwort »geheim« abschicken, werden Sie erfolgreich angemeldet, es wird eine Flash-Message ausgegeben, dass Sie erfolgreich angemeldet sind, und es werden Ihnen alle Links zum Arbeiten in der Bookmarkverwaltung angezeigt.

Abbildung  Erfolgreiche Anmeldung

logout

Damit wir uns nach erfolgreicher Anmeldung auch wieder abmelden können, brauchen wir noch eine Action logout im Controller authentication . Beim Log-out wird die Session gelöscht, es wird eine Flash-Message ausgegeben, dass der User abgemeldet wurde, und es wird zur Index-Seite der Bookmarkverwaltung weitergeleitet:

def logout
  reset_session
  flash[:notice] = "Sie wurden abgemeldet"
  redirect_to :controller => "bookmarks", :action => "index"
end

Damit wir den Log-out nicht über die URL aufrufen müssen, benötigen wir noch einen Link zum Log-out bzw. auch für den Log-in. Da dieser Link für alle Views angezeigt werden soll, definieren wir ihn in der application.html.erb im Verzeichnis app/views/layouts:

Listing  app/views/layouts/application.html.erb

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
  <meta http-equiv="Content-type" content="text/html;
  charset=utf-8" >
  <title>Favoritenverwaltung - <%= @title %></title>
  <%= stylesheet_link_tag 'global' %>

</head>
<body>
  <div id="container" >
    <div id="header" >
      <h1>Meine Linksammlung</h1>
    </div>
    <div id="content" >
      <% if flash[:notice] %>
        <div class="flash notice" >
          <%= flash[:notice] %>
        </div>
      <% end %>
      <%= yield %>
    </div>

    <div id="footer" >
      &copy; 2007 |
      <% if admin? %>
        <%= link_to "logout", :controller => "authentication",
      	      :action => "logout" %>
      <% else%>
        <%= link_to "login", :controller => "authentication",
	      :action => "login" %>
      <% end %>
    </div>
  </div>
</body>
</html>

Abbildung  Log-out-Link

Error-Message

Wenn wir uns mit einem falschen Benutzernamen anmelden, fällt auf, dass die Fehlermeldung genauso formatiert ist wie die Bestätigungsmeldungen. Das liegt daran, dass wir sowohl für die Bestätigungsmeldungen als auch für die Fehlermeldungen flash[:notice] benutzen. Für die Fehlermeldungen sollten wir aber besser flash[:error] verwenden. Wenn wir das tun, werden die Fehlermeldungen rot formatiert, weil wir das bereits entsprechend in unserer CSS-Datei hinterlegt haben. Voraussetzung ist allerdings, dass wir in der application.html.erb auch noch die Error-Messages ausgeben:

Listing  app/views/layouts/application.html.erb

...
<div id="container" >
  <div id="header" >
    <h1>Meine Linksammlung</h1>
  </div>
  <div id="content" >
    <% if flash[:notice] %>
      <div class="flash notice" >
        <%= flash[:notice] %>
      </div>
    <% end %>
    <% if flash[:error] %>
      <div class="flash error" >
        <%= flash[:error] %>
      </div>
    <% end %>
    <%= yield %>
...

Sicherheitslücke

Man könnte annehmen, wir wären fertig. Die Links zum Ändern und Hinzufügen eines Bookmarks werden nur nach einer erfolgreichen Anmeldung angezeigt. Da wir nur die Anzeige der Links unterdrückt haben, ist das eine erhebliche Sicherheitslücke in unserem System. Ein nicht angemeldeter User kann durch händisches Eingeben der URL

http://localhost:3000/bookmarks/edit/1

einen Datensatz ändern!

Um das zu verhindern, müssen wir im Bookmarks-Controller festlegen, dass ein Zugriff nur dann erlaubt ist, wenn der User, der versucht, auf die Actions new, edit und destroy zuzugreifen, angemeldet ist. Dazu stellt uns Rails die Methode verify zur Verfügung, der wir angeben müssen, welchen Wert sie überprüfen soll. In unserem Fall ist das die Session-Variable admin . Wenn sie nicht gesetzt ist, soll eine Fehlermeldung ausgegeben und der User zum Log-in-Formular weitergeleitet werden:

Listing  app/controllers/bookmarks_controller.rb

class BookmarksController < ApplicationController

verify :session => :admin,
       :add_flash => {:error => "Sie sind nicht angemeldet!"},
       :redirect_to => {:controller => "authentication",
       :action => "login"}
...

Wenn wir jetzt noch einmal versuchen, einen Datensatz zu ändern, indem wir die URL

http://localhost:3000/bookmarks/edit/1

aufrufen, werden wir zum Log-in-Formular weitergeleitet, und es wird die Fehlermeldung »Sie sind nicht angemeldet!« angezeigt.

Fertig? - Nein.

Denn wenn wir uns jetzt anmelden und anschließend wieder abmelden, haben wir ein Problem:

Abbildung  Abmelden mit implementierter verify-Methode

Ausnahme definieren

Da beim Abmelden unsere Session gelöscht wird und wir zur Index-Seite weitergeleitet werden, wir aber im Bookmarks-Controller definiert haben, dass alle Actions dieses Controllers nur für authentifizierte User zugänglich sind, trifft das auch auf die Index-Seite zu. Das soll aber prinzipiell nicht so sein, weil wir eigentlich wollten, dass die Index-Seite für alle User zugänglich ist. Gleiches gilt für den Aufruf der Detailseite, also der Action show . Das heißt, wir müssen eine Ausnahme definieren. Die verify -Methode soll für alle Actions aufgerufen werden, außer für die index und für die show:

Listing  app/controllers/bookmarks_controller.rb

class BookmarksController < ApplicationController

verify :except => ["index", "show"],
       :session => :admin,
       :add_flash => {:error => "Sie sind nicht angemeldet!"},
       :redirect_to => {:controller => "authentication",
       :action => "login"}
...

Jetzt ist die Authentifizierung unserer Bookmarkverwaltung fertig! Sie haben nun anhand eines relativ einfachen Authentifizierungssystems die Prinzipien kennengelernt, die auch aufwendigen Authentifizierungssystemen mit datenbankgestützter User-Verwaltung zugrunde liegen.



Ihr Kommentar

Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen. >> Zum Feedback-Formular
 <<   zurück
  Zum Katalog
Zum Katalog: Ruby on Rails 2
Ruby on Rails 2
Jetzt bestellen
 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchtipps
Zum Katalog: Ruby on Rails 3.1






 Ruby on Rails 3.1


Zum Katalog: Responsive Webdesign






 Responsive Webdesign


Zum Katalog: Suchmaschinen-Optimierung






 Suchmaschinen-
 Optimierung


Zum Katalog: JavaScript






 JavaScript


Zum Katalog: Schrödinger lernt HTML5, CSS3 und JavaScript






 Schrödinger lernt
 HTML5, CSS3
 und JavaScript


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo




Copyright © Rheinwerk Verlag GmbH 2008
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Rheinwerk Computing]

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de