47.23.1. Jednoduchá kontrola přístupu

Začnu tím nejjednodušším řešením. Potřebujeme ochránit přístup k naší aplikaci nebo její části. Začneme třeba u řadiče Listy řídicího zobrazení servisních listů. Chceme aby neautorizovaní uživatelé měli jen možnost založit nový servisní list a nikoliv si prohlížet již založené servisní listy.

V řadiči tedy definuji soukromou metodu login_required:

    private

    def login_required
        unless session[:user_name]
            flash[:error] = 'Pro přístup k této stráunce musíte být přihlášen(a).'
	    redirect_to :action => 'public_index'
        end
    end

Tato metoda nědělá nic jiného, než že zkontroluje jestli je uživatel přihlášený a v případě že nikoliv, připraví o tom zprávu a přesměruje jej na nějakou veřejnou stránku. Nějaká veřejná stránka se míní taková, která není kontrolována a kterou smí vidět i neutorizovaný uživatel. Může to být například přihlašovací stránka.

Nyní můžeme v řadiči definovat filtr který ochrání stránky. K tomu použijeme before_filter. V případě že chceme ochránít přístup jen k několika vybraným stránkám, definujeme filtr takto:

    before_filter :login_required, :only => [:edit, :destroy, :secret]

Pokud naopak chceme uživateli zamezit přístup všude, s výjimkou několika „veřejných“ stránek, napíšeme filtr takto:

    before_filter :login_required, :except => [:login, :public_index, :new, :show, :edit]

V tété chvíli nám již aplikace neumožní přístup na neveřejné stránky. Při přístupu na nevěřejnou stránku je připravena zpráva flash[:error], kterou zobrazíme v layoutu. Protože s oblibou používám layout aplikace, uvedu do něj mezi jinými:

Příklad 47.16. app/views/layouts/application.html.erb:

    <div id="pagecontent">
        <%= "<div class=\"error\">#{flash[:error]}</div>" if flash[:error] -%>
        <%= "<div class=\"info\">#{flash[:info]}</div>" if flash[:info] -%>
        <%= "<div class=\"notice\">#{flash[:notice]}</div>" if flash[:notice] -%>
        < yield -%>
    </div>
	    

Dalším krokem je umožnit uživateli přihlášení, tedy implemetovat metodu login s její formulář.

Příklad 47.17. app/controllers/listy_controller.rb:

    def login
        if request.post?
            if params[:login][:user_name] == 'admin' && params[:login][:password] == 'žížala'
                session[:user_name] == params[:login][:user_name]
		redirect_to :action => 'index'
            else
                @auth_error = 'Špatné jméno nebo heslo'
            end
        end
    end

To be done.

Začnu úpravou datového modelu uživatelů aplikace. Tento model, jenž se často jmenuje User s v mém případě jmenuje Person. Ale na jménu nezáleží. Tento model rozšíříme o metody umožňující ověření uživatele. V první variantě nebudu ukládat hesla ani jména do tabulky, protože budu mít jen jednoho „administrátora“ jehož přístup k aplikaci nebude omezován.

Pokud chceme ověřovat uživatele podle databáze, provedeme pár úprav. Nejdříve musíme mít v databázi uživatelská jména a hesla.

Příklad 47.18. db/migrate/999_add_credentials:

class AddCredentials < ActiveRecord::Migration
    def self.up
        add_column      :person, :login, :string, :limit => 16, …
        add_column      :person, :sha1hash, :string, :limit => 34 …
    end
    def self.down
        remove_column   :person, :login
        remove_column   :person, :sha1hash
    end
end

V modelu pak nejdříve definujeme metodu pro vytváření hashe z hesla. Tu jsem pojmenoval po metodě kterou používám, tedy sha1_digest. Metodě předávám jeden zatím nevyužitý parametr a to salt.

Příklad 47.19. app/models/person.rb:

require 'digest/sha1'

class Person < ActiveRecord::Base

    def self.sha1_digest(password, salt=nil)
        '{SHA}'+Base64.encode64(Digest::SHA1.digest(password)).chomp
    end
end

Metodu si odzkoušíme:

$ script/console
Loading development environment (Rails 2.0.2)
>> Person.sha1_digest('heslo')
=> "{SHA}bgF7VGT4IKbBu16fbXEaZnqA2Oo="

Nyní napíšeme metodu pro ověření uživatele authenticate

Příklad 47.20. app/models/person.rb:

    def self.authenticate(login, password)
        user = find(:first, :conditions => ['login = ?', login])
        return nil if user.nil?
        return user if (Person.sha1_digest(password) == user.sha1hash)
        nil
    end

Licence Creative Commons
Tento dokument Ruby, jehož autorem je Radek Hnilica, podléhá licenci Creative Commons Uveďte autora-Nevyužívejte dílo komerčně-Zachovejte licenci 3.0 Česká republika .