2010-08-02 6 views
9

Ich verwende Zend_Auth zur Authentifizierung in einem Webportal.Zend_Auth: Erlaube dem Benutzer bei mehreren Tabellen/Identitäten angemeldet zu sein

Ein normaler mySQL „Benutzer“ Tabelle mit einem login und password Spalte wird abgefragt gegen, und ein Benutzer angemeldet.

Ich habe jedoch zwei zusätzliche Gruppen von Benutzern, die ich authentifizieren möchten. Alle drei dieser Benutzergruppen haben ihre Anmeldedaten in anderen Tabellen. Ihre Daten stammen von externen Quellen, daher ist es nicht erwünscht, diese Login-Konten zu einem zu vereinigen.

So könnte es sein, dass ein Benutzer ein authentifizierter Benutzer aus einer der drei Gruppen ist, auch alle drei, gleichzeitig.

Jede der drei Login-Gruppen hat ihr eigenes Login-Formular und ihren Logout-Button.

Im Moment habe ich eine einzige, einfache Zend_Auth Login, von einem Tutorial genommen und leicht modifiziert, die ungefähr wie folgt aussieht:

function login($user, $password) 
{ 

$auth = Zend_Auth::getInstance(); 
$storage = new Zend_Auth_Storage_Session(); 

$auth->setStorage($storage); 

$adapter = new Zend_Auth_Adapter_DbTable(....); 

$adapter->setIdentity($username)->setCredential($password); 

$result = $auth->authenticate($adapter); 

if ($result->isValid()) 
......... success! 
else 
.... fail! 

wo ich würde das dienen und Anschrift anfangen zu machen getrennte "eingeloggte" Zustände für die drei Gruppen? Meine Idee ist, dass ich die Sitzung teilen und die Authentifizierungen getrennt verwalten möchte.

Ist das möglich? Vielleicht gibt es ein einfaches Präfix, das das einfach macht? Gibt es Tutorials oder Ressourcen zu diesem Problem?

Ich bin ein relativer Neuling zum Zend Framework.

+0

Müssen Sie haben unterschiedliche Identitäten für jede Gruppe verwenden würde? Oder ist es nur eine Frage der Authentifizierung gegen einen anderen Tisch? – Gordon

+0

@Gordon müssten sie separate Identitäten sein (sagen wir CMS-Nutzer, Großhändler und Endbenutzer). Ich könnte alle drei Dinge gleichzeitig sein. –

+0

Prior ZF Dies war die Domäne von PEAR :: LiveUser. http://devzone.zend.com/node/view/id/1001 – mario

Antwort

10

Sie sollten Ihren eigenen Zend_Auth_Adapter erstellen. Dieser Adapter wird versuchen, sich gegen Ihre drei Ressourcen zu authentifizieren und wird ihn in einer privaten Mitgliedsvariablen kennzeichnen, so dass Sie wissen können, welche der Anmeldeversuche erfolgreich authentifiziert wurden.

Um Ihren Auth Adapter zu erstellen, können Sie die Zend_Auth_Adapter_DbTable als Grundlage nehmen.

Also, in der __construct statt nur einen DbTable-Adapter übergeben, können Sie die drei Adapter in jeder Ressource übergeben. Sie werden nur dann auf diese Weise arbeiten, wenn jeder andere Ressourcen verwendet, wie z. B. LDAP oder sogar eine andere Datenbank. Wenn nicht, können Sie nur einen Adapter übergeben und drei verschiedene Tabellennamen in den Konfigurationsoptionen festlegen. Hier

ist das Beispiel von Zend_Auth_Adapter_DbTable:

/** 
    * __construct() - Sets configuration options 
    * 
    * @param Zend_Db_Adapter_Abstract $zendDb 
    * @param string     $tableName 
    * @param string     $identityColumn 
    * @param string     $credentialColumn 
    * @param string     $credentialTreatment 
    * @return void 
    */ 
    public function __construct(Zend_Db_Adapter_Abstract $zendDb, $tableName = null, $identityColumn = null, 
           $credentialColumn = null, $credentialTreatment = null) 
    { 
     $this->_zendDb = $zendDb; 

     // Here you can set three table names instead of one 
     if (null !== $tableName) { 
      $this->setTableName($tableName); 
     } 

     if (null !== $identityColumn) { 
      $this->setIdentityColumn($identityColumn); 
     } 

     if (null !== $credentialColumn) { 
      $this->setCredentialColumn($credentialColumn); 
     } 

     if (null !== $credentialTreatment) { 
      $this->setCredentialTreatment($credentialTreatment); 
     } 
    } 

Das Verfahren unten, von Zend_Auth_Adapter_DbTable, versuchen gegen einen Tisch zu authentifizieren, können Sie es ändern in drei Tabellen, um zu versuchen, und für jeden, wenn Sie bekommen Sucess , legen Sie dies als ein Flag in der privaten Membervariable fest. Etwas wie $ result ['group1'] = 1; Sie geben 1 für jeden erfolgreichen Anmeldeversuch ein.

/** 
* authenticate() - defined by Zend_Auth_Adapter_Interface. This method is called to 
* attempt an authentication. Previous to this call, this adapter would have already 
* been configured with all necessary information to successfully connect to a database 
* table and attempt to find a record matching the provided identity. 
* 
* @throws Zend_Auth_Adapter_Exception if answering the authentication query is impossible 
* @return Zend_Auth_Result 
*/ 
public function authenticate() 
{ 
    $this->_authenticateSetup(); 
    $dbSelect = $this->_authenticateCreateSelect(); 
    $resultIdentities = $this->_authenticateQuerySelect($dbSelect); 

    if (($authResult = $this->_authenticateValidateResultset($resultIdentities)) instanceof Zend_Auth_Result) { 
     return $authResult; 
    } 

    $authResult = $this->_authenticateValidateResult(array_shift($resultIdentities)); 
    return $authResult; 
} 

Sie eine gültige $ authresult nur zurück, wenn einer der drei Anmeldeversuche wurden erfolgreich authentifiziert.

Jetzt in Ihrem Controller, nach versuchen Sie sich anmelden:

public function loginAction() 
{ 
    $form = new Admin_Form_Login(); 

    if($this->getRequest()->isPost()) 
    { 
     $formData = $this->_request->getPost(); 

     if($form->isValid($formData)) 
     { 

      $authAdapter = $this->getAuthAdapter(); 
       $authAdapter->setIdentity($form->getValue('user')) 
          ->setCredential($form->getValue('password')); 
       $result = $authAdapter->authenticate(); 

       if($result->isValid()) 
       { 
        $identity = $authAdapter->getResult(); 
        Zend_Auth::getInstance()->getStorage()->write($identity); 

        // redirect here 
       }   
     } 

    } 

    $this->view->form = $form; 

} 

private function getAuthAdapter() 
{ 
    $authAdapter = new MyAuthAdapter(Zend_Db_Table::getDefaultAdapter()); 
    // Here the three tables 
    $authAdapter->setTableName(array('users','users2','users3')) 
       ->setIdentityColumn('user') 
       ->setCredentialColumn('password') 
       ->setCredentialTreatment('MD5(?)'); 
    return $authAdapter;  
} 

Der Schlüssel hier ist die Linie unten, die in Ihrer benutzerdefinierten Auth Adapter implemeted werden:

$identity = $authAdapter->getResult(); 

Sie können nehmen diese Form Zend_Auth_Adapter_DbTable als Basis:

/** 
    * getResultRowObject() - Returns the result row as a stdClass object 
    * 
    * @param string|array $returnColumns 
    * @param string|array $omitColumns 
    * @return stdClass|boolean 
    */ 
    public function getResultRowObject($returnColumns = null, $omitColumns = null) 
    { 
     // ... 
    } 

die Zeile Diese Rückkehr in die Anmeldung ein angepaßtes tmtemp wenn erfolgreich authentifiziert. Sie werden also Ihre Methode getResult() erstellen, die diese Zeile und die Flags $ this-> result ['groupX'] zurückgeben kann. Etwas wie:

public function authenticate() 
{ 
    // Perform the query for table 1 here and if ok: 
    $this->result = $row->toArrray(); // Here you can get the table result of just one table or even merge all in one array if necessary 
    $this->result['group1'] = 1; 

    // and so on... 
    $this->result['group2'] = 1; 

    // ... 
    $this->result['group3'] = 1; 

    // Else you will set all to 0 and return a fail result 
} 

public function getResult() 
{ 
    return $this->result; 
} 

Schließlich können Sie Zend_Acl verwenden Kontrolle über Ihre Ansichten und andere Maßnahmen zu ergreifen. Da Sie die Flaggen in der Zend Auth Speicher haben, können Sie als als Rollen verwenden:

http://framework.zend.com/manual/en/zend.auth.introduction.html

http://zendguru.wordpress.com/2008/11/06/zend-framework-auth-with-examples/

http://alex-tech-adventures.com/development/zend-framework/61-zendauth-and-zendform.html

:

$this->addRole(new Zend_Acl_Role($row['group1'])); 

Hier einige Ressourcen http://alex-tech-adventures.com/development/zend-framework/62-allocation-resources-and-permissions-with-zendacl.html

http://alex-tech-adventures.com/development/zend-framework/68-zendregistry-and-authentication-improvement.html

+0

Sehr nett. Ich werde das prüfen und wenn ich damit arbeiten kann, implementieren Sie es sofort. Es könnte ein paar Tage dauern, aber ich werde auf jeden Fall mit Feedback zurück sein. –

+0

+1 eine benutzerdefinierte Auth-Adapter wäre wahrscheinlich die beste Idee.für die, die was tun können, auf was teil verwenden zend_acl – robertbasic

+0

@Pekka Hast du es geschafft? Irgendwelche Probleme? –

1

Warum nicht einfach eine Ansicht erstellen, die alle 3 Tabellen zusammenführt, und sich dann mit dieser Ansicht authentifizieren?

+0

Das gibt mir nicht die Möglichkeit, in einer der drei Tabellen gleichzeitig angemeldet zu sein. –

+0

danke, es ist sehr hilfreich für mich –

3

Ich nahm etwas Inspiration von der Zym_Auth_Adapter_Chain, aber änderte es leicht, damit es nicht auf dem ersten Adapter stoppt, der erfolgreich zurückkehrt.

require_once 'Zend/Auth/Adapter/Interface.php'; 
require_once 'Zend/Auth/Result.php'; 

class My_Auth_Adapter_Chain implements Zend_Auth_Adapter_Interface 
{ 
    private $_adapters = array(); 

    public function authenticate() 
    { 
     $adapters = $this->getAdapters(); 

     $results  = array(); 
     $resultMessages = array(); 
     foreach ($adapters as $adapter) { 
      // Validate adapter 
      if (!$adapter instanceof Zend_Auth_Adapter_Interface) { 
       require_once 'Zend/Auth/Adapter/Exception.php'; 
       throw new Zend_Auth_Adapter_Exception(sprintf(
        'Adapter "%s" is not an instance of Zend_Auth_Adapter_Interface', 
       get_class($adapter))); 
      } 

      $result = $adapter->authenticate(); 

      if ($result->isValid()) { 
       if ($adapter instanceof Zend_Auth_Adapter_DbTable) { 
        $results[] = $adapter->getResultRowObject(); 
       } 
       else { 
        $results[] = $result->getIdentity(); 
       } 
      } 
      else { 
       $resultMessages[] = $result->getMessages(); 
      } 
     } 
     if (!empty($results)) { 
      // At least one adapter succeeded, return SUCCESS 
      return new Zend_Auth_Result(Zend_Auth_Result::SUCCESS, $results, $resultMessages); 
     } 

     return new Zend_Auth_Result(Zend_Auth_Result::FAILURE, null, $resultMessages); 
    } 

    public function getAdapters() 
    { 
     return $this->_adapters; 
    } 

    public function addAdapter(Zend_Auth_Adapter_Interface $adapter) 
    { 
     $this->_adapters[] = $adapter; 
     return $this; 
    } 

    public function setAdapters(array $adapters) 
    { 
     $this->_adapters = $adapters; 
     return $this; 
    } 
} 

Um es von einem Controller rufen Sie einfach die Kette erstellen, dann die Adapter Sie (in Ihrem Fall wird dieser wahrscheinlich ein DB-Adapter pro Einheit Tisch) und schließlich die Adapter übergeben an die Kette verwenden möchten .

$db = Zend_Db_Table::getDefaultAdapter(); 

// Setup adapters 
$dbAdminsAdapter = new Zend_Auth_Adapter_DbTable($db, 'admins');  
$dbAdminsAdapter->setIdentityColumn('login') 
       ->setCredentialColumn('password') 
       ->setIdentity($login) 
       ->setCredential($password); 

$dbUsersAdapter = new Zend_Auth_Adapter_DbTable($db, 'users'); 
$dbUsersAdapter->setIdentityColumn('login') 
       ->setCredentialColumn('password') 
       ->setIdentity($login) 
       ->setCredential($password); 
... 

// Setup chain 
$chain = new My_Auth_Adapter_Chain(); 
$chain->addAdapter($dbAdminsAdapter) 
     ->addAdapter($dbUsersAdapter); 

// Do authentication 
$auth = Zend_Auth::getInstance(); 
$result = $auth->authenticate($chain); 
if ($result->isValid()) { 
    // succesfully logged in 
} 

Dieser Code nur einfaches Beispiel ist, möchten Sie wahrscheinlich setCredentialTreatment auch auf die DbTable Adapter verwenden ...

Der Vorteil dieses Ansatzes ist, dass es trivial sein wird anderen vorhandenen Adapter für andere hinzufügen Formen der Authentifizierung (dh. OpenID) zu der Kette später ...

Der Nachteil: wie Sie erhalten ein Array als Ergebnis von jedem Aufruf an Zend_Auth :: getInstance() -> getIdentity() ;. Sie können dies natürlich im Kettenadapter ändern, aber das bleibt Ihnen überlassen: p.

DISCLAIMER: Ich glaube wirklich nicht, dass es klug ist, es so zu machen. Um dies zu ermöglichen, müssen Sie den gleichen Benutzernamen und das gleiche Kennwort für die verschiedenen Tabellen verwenden. Wenn ein Benutzer mehr als eine Rolle (Identität) hat, müssen Sie sicherstellen, dass diese Änderung an alle Identitätstabellen weitergegeben wird Benutzer hat ein Konto. Aber ich höre jetzt auf zu nörgeln: p.

2

Da Zend_Auth ein Singleton ist, löst das Erstellen von benutzerdefinierten Auth-Adaptern für jede Authentifizierungsquelle nur die erste Hälfte dieses Problems. Die zweite Hälfte des Problems besteht darin, dass Sie sich gleichzeitig mit mehreren Konten anmelden können: jeweils eine Authentifizierungsquelle.

Ich fragte eine similar question recently. Die Lösung bestand darin, Zend_Auth zu erweitern, wie in der angenommenen Antwort gezeigt. Ich initialisiere dann die verschiedenen Authentifizierungstypen in meinem Bootstrap.

protected function _initAuth() 
{ 
    Zend_Registry::set('auth1', new My_Auth('auth1')); 
    Zend_Registry::set('auth2', new My_Auth('auth2')); 
    Zend_Registry::set('auth3', new My_Auth('auth3')); 
} 

Also, statt des Singletons Zend_Auth::getInstance() Sie Zend_Registry::get('auth1') usw.

Verwandte Themen