2009年9月30日星期三

Re: [fw-auth] a couple questions about customizing Zend_Auth



On Tue, Sep 29, 2009 at 2:04 PM, Ralph Schindler <ralph.schindler@zend.com> wrote:


used getDbSelect() to get the select and join() a table, and could not

This is a bug in Zend_Db_Select. Currently, calling join before from
causes odd SQL to be produced.  It seems like fixing this issue:

http://framework.zend.com/issues/browse/ZF-6653

will probably solve yours.  I have this slated for an upcoming release.




Interesting, and not entirely surprising. Most people probably think of building their SQL from left to right, so the join() before from() would be an unusual case that you can easily forgive developers for not anticipating.


 

and kept getting Zend_Auth_Adapter_Exception, invalid SQL statement.

In any event, I gave up on this approach and am now extending Zend_Auth_Adapter_DbTable and overriding authenticate(). Is this a reasonable solution?

This is a very reasonable solution, in fact, it was designed for.  You
can see that since there are several small succinct methods that you can
override in Zend_Auth_Adapter_DbTable.


I extended Zend_Auth_Adapter_DbTable and implemented my own authenticate(), leveraging a couple of protected methods from the parent, stealing whoever's clever snippet that builds the boolean 'zend_auth_credential_match' expression, and adding the stuff I needed, e.g, a rather tortured SQL query because of my weird database structure, and a database update to set the users last_login timestamp. Works great.

 

Which brings me to the next question:  suppose you want to add an authentication failure code that means 'account disabled.'  Extend Zend_Auth_Result and have your authenticate return an instance of it?

It sounds like you want to build an Auth model, and inside that model,
extends Zend_Auth_Adapter_DbTable to detect this situation.  I would
return the standard failure constant, but also add the message that you
feel you might want to use as the failure message.


Well, yeah -- if I understand correctly, that's what I've done.

Model_AuthAdapter extends Zend_Auth_Adapter_DbTable
{

const FAILURE_ACCOUNT_DISABLED = 'Account disabled.';

function authenticate() {
      
        $this->_authenticateResultInfo['identity'] = $this->_identity;
         // stolen from parent
        if (empty($this->_credentialTreatment) || (strpos($this->_credentialTreatment, '?') === false)) {
            $this->_credentialTreatment = '?';
        }
        $credentialExpression = new Zend_Db_Expr(
            '(CASE WHEN ' .
            $this->_zendDb->quoteInto(
                $this->_zendDb->quoteIdentifier($this->_credentialColumn, true)
                . ' = ' . $this->_credentialTreatment, $this->_credential
                )
            . ' THEN 1 ELSE 0 END) AS '
            . $this->_zendDb->quoteIdentifier('zend_auth_credential_match')
            );
        // end stolen part
        if ($this->_identityColumn == 'username') {
            $identityColumn = 'users.username';
        } elseif ($this->_identityColumn == 'email') {
            $identityColumn = 'people.email';
        } else {
            throw new Exception('invalid identity column: '.$this->_identityColumn);
        }
        $select = $this->_zendDb->select();
        $select
            ->from($this->_tableName, array('username','group_id','active','last_login', $credentialExpression))
            ->join('groups','users.group_id = groups.id',array('group'=>'groups.name'))
            ->join('people','users.person_id = people.id',array('id','lastname','firstname','email'))
            ->join('person_types','people.person_type_id = person_types.id',array('person_type'=>'flavor'))
            ->where("$identityColumn = ? ",$this->_identity) ;
      
        $this->_zendDb->setFetchMode(Zend_Db::FETCH_OBJ);
        $results = $this->_zendDb->fetchAll($select);
        // borrowed from parent
        if ( ($authResult = $this->_authenticateValidateResultset($results)) instanceof Zend_Auth_Result) {
            return $authResult;
        }
        $user = array_shift($results);
        $authResult = $this->_authenticateValidateResult((array)$user);
        // if everything is good so far, make sure account is active
        if ($authResult->isValid()) {
            if (! $user->active) {
                return new Zend_Auth_Result(Zend_Auth_Result::FAILURE_UNCATEGORIZED,
                    $this->_identity,array(self::FAILURE_ACCOUNT_DISABLED));
            }
        }
        $this->_zendDb->update('users',   array('last_login' => time()),           $this->_zendDb->quoteInto( 'person_id = ?', $user->id ) );
         return $authResult;
    }

}

Thank you Ralph.

--
David Mintz
http://davidmintz.org/

The subtle source is clear and bright
The tributary streams flow through the darkness

没有评论: