Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [ZendFramework] uwierzytelnianie z dodatkowym parametrem
Forum PHP.pl > Forum > PHP > Frameworki
czachor
Witam,

kombinuję dzisiaj z Zend_Auth i coś mi nie idzie... Chciałbym, żeby oprócz standardowego sprawdzania nazwy i hasła w bazie spełniony był również warunek 'active = TRUE'.
Mam kod z manuala, ale nie działa, logują się nieaktywowani użytkownicy...

Niżej mój kod. Wszystko jest ok, tylko zupełnie ignorowany jest warunek... Będę wdzięczny za pomoc.
  1. <?php
  2. class LoginController extends Main_Controller_Action
  3. {
  4.    function indexAction()
  5.    {
  6.        if ($this->_request->isPost())
  7.        {
  8.            $f = new Zend_Filter_HtmlEntities(ENT_QUOTES);
  9.            $username = $f->filter($this->_request->getPost('user'));
  10.            $password = sha1($f->filter($this->_request->getPost('upasid')));
  11.  
  12.            if (empty($username))
  13.            {
  14.                $this->view->message = 'Nie podano nazwy użytkownika.';
  15.            }
  16.            else
  17.            {
  18.                $db = Zend_Registry::get('db');
  19.                $authAdapter = new Zend_Auth_Adapter_DbTable($db,
  20.                    'users',
  21.                    'name',
  22.                    'password',
  23.                    ' AND active = TRUE');
  24.  
  25.                //$authAdapter->setTableName('users');
  26.                //$authAdapter->setIdentityColumn('name');
  27.                //$authAdapter->setCredentialColumn('password');
  28.                $authAdapter->setIdentity($username);
  29.                $authAdapter->setCredential($password);
  30.  
  31.                $auth = Zend_Auth::getInstance();
  32.                $result = $auth->authenticate($authAdapter);
  33.  
  34.                switch ($result->getCode())
  35.                {
  36.                    case Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND:
  37.                        //nieistniejący użytkownik
  38.                        $this->view->message = 'Użytkownik o podanym loginie nie istnieje.';
  39.                    break;
  40.  
  41.                    case Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID:
  42.                        //niepoprawne hasło
  43.                        $this->view->message = 'Nieprawidłowe hasło.';
  44.                    break;
  45.  
  46.                    case Zend_Auth_Result::SUCCESS:
  47.                        //sukces
  48.                        if ($result->isValid())
  49.                        {
  50.                            $data = $authAdapter->getResultRowObject(null, 'password');
  51.                            $auth->getStorage()->write($data);
  52.                            $this->_redirect('somewhere');
  53.                        };
  54.                    break;
  55.  
  56.                    default:
  57.                        //to do
  58.                    break;
  59.                };
  60.            };
  61.        };
  62.    }
  63. }
  64. ?>
batman
Nie do końca zrobiłeś jak w manualu.
Nie widzę sprawdzenia hasła (MD5(?)) - chyba, że nie masz haseł zapisanych w md5. Poza tym TRUE powinno być w cudzysłowie - "TRUE". No i na koniec nie jestem pewien, czy powinien być ten pierwszy AND.
gazelek
Pozwole sie podpiac. Wykorzystuje powyzszy przyklad z manuala. Chcialem zrobic dwa logowania w obrebie jednej strony (jedno dla uzytkownika, drugie dla administratora). Wykorzystujac ten przyklad uzytkownik po zalogowaniu sie uzyskuje dostep rowniez do panelu administracyjnego. Czy jest jakas metoda rozwiazania tego po stronie skryptu? Bo jedyne, co mi przychodzi teraz na mysl, to usuniecie tabeli administratorow i nadawanie uzytkownikom praw dostepu, ale to rozwiazanie po stronie bazy danych....
czachor
Racja, jest trochę inaczej. Nie zrobiłem sprawdzania hasła, bo używam sha1, a baza to postgres (błąd, nie napisałem od razu). Pogrzebałem trochę w kodzie Zend_Auth i doszedłem do tego, że musi tam być znak zapytania. Po kilku próbach w PostgreSQL'u zadziałała taka konstrukcja (trochę zmieniona do powyższej, ale de facto jest to to samo):
  1. <?php
  2. $authAdapter = new Zend_Auth_Adapter_DbTable($db);
  3. $authAdapter->setTableName('users');
  4. $authAdapter->setIdentityColumn('name');
  5. $authAdapter->setCredentialColumn('password');
  6. $authAdapter->setCredentialTreatment('? AND active = TRUE');
  7. $authAdapter->setIdentity($username);
  8. $authAdapter->setCredential($password);
  9. ?>

Moje spostrzeżenie: w postgresie nie działa konstrukcja podana w dokumentacji ZF (chodzi o cudzysłowia):
  1. <?php
  2. $authAdapter->setCredentialTreatment('? AND active = "TRUE"');
  3. ?>

Nie ma również wbudowanej funkcji SHA1, więc robię to na poziomie php. Gdyby ktoś chciał, można ją sobie dorzucić do bazy:
  1. CREATE OR REPLACE FUNCTION sha1(bytea) returns text AS $$
  2. SELECT encode(digest($1, 'sha1'), 'hex')
  3. $$ LANGUAGE SQL STRICT IMMUTABLE;

a potem:
  1. <?php
  2. $authAdapter->setCredentialTreatment('SHA1(?) AND active = TRUE');
  3. ?>
batman
Cytat(gazelek @ 29.04.2009, 13:09:54 ) *
Chcialem zrobic dwa logowania w obrebie jednej strony (jedno dla uzytkownika, drugie dla administratora).

Logowanie robisz jedno. Musisz odpowiednio nadać prawa dostępu. Poczytaj o Zend_Acl.

~czachor
O ile się nie myle to w pg w kolumnach typu bool jest t i f zapisane. Z tego właśnie powodu wszystkie wartości true/false zapisuję jako smallint/tinyint. O wiele łatwiej przesiąść się na inną bazę danych.
Jeśli nie podasz znaku zapytania, zostanie on dopisany automatycznie.
czachor
Fakt, znak zapytania dopisał się sam.
Co do pg bool:
Cytat(manual pg)
boolean can have one of only two states: "true" or "false".
Valid literal values for the "true" state are:

TRUE
't'
'true'
'y'
'yes'
'1'

For the "false" state, the following values can be used:

FALSE
'f'
'false'
'n'
'no'
'0'

Wiem, że kiedyś był z tym problem, ale od którejś wersji pg zniknął. W eksporcie też mam true/false, więc może zależy teraz to od tego, co się w to pole wstawiło.
gazelek
Cytat(batman @ 29.04.2009, 14:14:47 ) *
Logowanie robisz jedno. Musisz odpowiednio nadać prawa dostępu. Poczytaj o Zend_Acl.


Jakos nie bylo czasu sie tym zajac, az do dzisiaj. Przeczytalem sekcje manuala dotyczaca Zend_Acl. Pogooglowalem troche, ale ciagle nie moge znalezc zwiazku miedzy Zend_Auth (za pomoca ktorego przeprowadzam logowanie) a wlasnie Zend_Acl. Na chlopski rozum - po zalogowaniu trzeba w jakis sposob ustawic rolę uzytkownika, ktory sie wlasnie zalogowal. Dobrze mysle? Bo skoro mam zdefiniowane:

Kod
$this->addRole(new Zend_Acl_Role('domyslna'));
$this->addRole(new Zend_Acl_Role('uzytkownik'),'domyslna');
$this->addRole(new Zend_Acl_Role('admin'), 'uzytkownik');

//ciach ciach, ponizej ustawienia resursow dla powyzszych rol


to w jaki sposob po logowaniu ustawic, jaka role pelni ten ktos, kto sie zalogowal?
batman
W tabeli użytkowników przechowujesz informację do jakiej roli należy użytkownik (przyjmijmy dla uproszczenia, że użytkownik może być przypisany tylko do jednej roli). Podczas logowania sprawdzasz do jakiej roli jest przypisany, a następnie sprawdzasz, czy rola ma dostęp do aktualnego zasobu (isAllowed). W ten oto prosty sposób masz rozwiązaną autentykację oraz autoryzację.
Sprawdzanie praw dostępu najlepiej zrobić w pluginie, by nie duplikować kodu.
gazelek
Sprawdzanie, o ktorym piszesz mialoby miejsce przy logowaniu. A jak rozwiazac ta kwestie na innych podstronach? Zakladam, ze user loguje sie na stronie glownej, a pozniej wklepuje w pasek adresu mojastrona.com/admin - czy dostep zostanie mu zablokowany z automatu, czy musze dodatkowo sprawdzac, czy ma uprawnienia? Bo zakladam, ze pelniona przez usera role zapisalbym np w sesji i pozniej to sprawdzal... no chyba, ze to sie robi jakos z automatu przy uzyciu Zend_Acl - nie chce dublowac kodu niepotrzebnie. Bo w sumie napisanie wlasnej klasy dziedziczacej z Zend_Acl, poszerzona o sprawdzanie autentykacji to nie jest problem....

Edit: dzieki za pomoc, juz sobie poradzilem, znalazlem przykladowy kod, ktory mi wszystko rozjasnil winksmiley.jpg
pgrzelka
kiedyś w jednym skrypcie zrobiłem coś takiego, może Ci pomoże ten kod
w pluginie tworzysz funkcję preDispatch, w niej pobierasz uprawnienia usera z bazy, tworzysz tablicę z tych uprawnień,
następnie sprawdzasz czy wywołany controller znajduje się w tablicy, jeśli nie to obsługujesz błąd.
kod nie jest doskonały, ale działa smile.gif
Kod
    public function preDispatch(Zend_Controller_Request_Abstract $request)
    {
        $m = $request->getModuleName();
        $c = $request->getControllerName();
           $session = Zend_Registry::get('session');

        $acc = $session->acc; // to jest wiersz pobrany z bazy danych przy logowani, a następnie zapisany w sesji,  kolejne kolumny a1,a2.. mają wartość 0 lub 1

        $allow = array();
        if ($acc['a1']) $allow[] = 'news';  // news to controller do którego albo ma dostęp albo nie ma dostępu
        if ($acc['a2']) $allow[] = 'polls';
        if ($acc['a3']) $allow[] = 'pages';
        if ($acc['a4']) $allow[] = 'album';
        if ($acc['a5']) $allow[] = 'regards';
        if ($acc['a6']) $allow[] = 'comments';
        
        if (!in_array($c,$allow))
        {
            $request->setControllerName('error');
            $request->setActionname('error');
            throw new Exception('', 403);    
        }
     }
gazelek
Pozwole sobie jeszcze poprosic o pomoc... ustawilem sobie juz wszystko (Zend_Registry, reguly do Zend_Acl, sesje), napisalem plugin (kod macie ponizej). Problem polega na tym, ze wszystkie parametry zmiennej $request (konkretnie te, ktore mnie interesuja: module, controller i action) maja wartosc NULL. Niezaleznie od tego, czy uzyje zmiennej z linijki 16 czy z 17... wlasciwie juz wszystko by mi mialo dzialac, poza tym zakichanym $request...
Dodam, ze var_dump($request) wykonany w ktorymkolwiek kontrollerze zwraca poprawny wynik...

Obiekt typu Jpg_Acl tworzony jest w pliku Initializer.php, wtedy tez przekazywany jest do niego $request, wiec moze wtedy nie ma tam przypisanych jeszcze modułu, kontrollera i akcji... Jak w takim razie to rozwiazac? Bo troche mi sie pomysly skonczyly, a jestem juz dosc blisko celu tongue.gif

Kod
<?php
    
    class Jpg_Acl extends Zend_Controller_Plugin_Abstract{
        
        protected $_acl;
        
        protected $_role;

        public function __construct($request,$acl,$rola='guest'){
            $this->_acl = $acl;
            $this->_role = $rola;
            $this->check($request);
        }
        
        public function check(Zend_Controller_Request_Abstract $request){
            var_dump($this->getRequest());
            //var_dump($request); zwraca taki sam wynik jak wyzej....
            $resourceName = $this->_request->getModuleName();
            if (!$this->_acl->isAllowed($this->_role, $resourceName, $request->getActionName())) {
                //$this->denyAccess($request);
            }
        }
        
        private function denyAccess(Zend_Controller_Request_Abstract $request){
            echo '<script language="javascript">location.replace("'.$request->getBaseUrl().'");</script>';
        }
    }
?>
pgrzelka
request ma jakąś wartość czy jest NULL ?

zrób w tym pluginie funkcję preDispatch($request) zamiast check();
w odpowiednim momencie zostanie ona wywołana przez frameworka, a zmienna $request będzie miała poprawne wartości, nie wywołuj sam tej funkcji.
gazelek
request ma wartosc, ale te trzy zmienne (module,controller i action) sa NULL. Po zmianie nazwy funkcji na preDispatch i dodaniu testowego napisu (echo "test";) on sie wogole nie wyswietla -> funkcja sie nie wykonuje...
Struktura katalogu library:
library/
Zend/
tutaj biblioteki Zenda
Jpg/
MyAcl.php

Pytanie - czy nie musze zrobic czegos na wzor pluginow Zenda? W sensie tak:
library/
Jpg/
Acl/
tu jakies pliki, w ktoryms z plikow tego katalogu funkcja preDispatch
MyAcl.php

Czy to ma jakies znaczenie? Bo mam akurat taki przykladowy kod zrodlowy (niestety, podzial tylko na dwie role) i tam to jest wlasnie tak rozwiazane.
pgrzelka
a jak tworzysz ten plugin?
new Jpg_Acl(zmienne);
czy
$frontcontroller -> registerPlugin(new Jpg_Acl(zmienne));

przeczytaj sobie to
http://framework.zend.com/manual/en/zend.c...er.plugins.html
gazelek
Brawo, o to wlasnie chodzilo. Wielkie dzieki, nie moge kliknac 'Pomogl' bo go nie ma, ale wysylam raport do moderatora, zeby Ci punkcik dodal! winksmiley.jpg
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.