I want to try it with zend authentication component. I'd like to use bcrypt algorithm with dbTable authentication adapter.
Unfortunately, ZF2 has no built-in auth adapter for this.
Ok, let's make our own auth adapter based on DbTable auth adapter.
The logic is:
- fetch all rows from table where identity column value is equal to value of identity field from login form(it could be login name, email, etc)
- check if entered password is valid using bcrypt->verify() method
Implementation:
1. Create class that extends DbTable auth adapter
// define namespace for the class namespace SomeModule\Auth\Adapter; class BcryptDbAdapter extends DbTable { }
2. It is necessary to redefine two methods in our new class.
First method: authenticateCreateSelect() - method that creates a Zend\Db\Sql\Select object for fetching data from database
Second method: authenticateQuerySelect() - method that fetches data from database using Zend\Db\Sql\Select object from previous method.
Our class will look like below:
namespace SomeModule\Auth\Adapter; use Zend\Authentication\Adapter\DbTable; use Zend\Db\Sql; use Zend\Db\Sql\Predicate\Operator as SqlOp; class BcryptDbAdapter extends DbTable { protected function authenticateCreateSelect() { // get select $dbSelect = clone $this->getDbSelect(); $dbSelect->from($this->tableName) ->columns(array('*')) ->where(new SqlOp($this->identityColumn, '=', $this->identity)); return $dbSelect; } protected function authenticateQuerySelect(Sql\Select $dbSelect) { $sql = new Sql\Sql($this->zendDb); $statement = $sql->prepareStatementForSqlObject($dbSelect); try { $result = $statement->execute(); $resultIdentities = array(); // create object ob Bcrypt class $bcrypt = new \Zend\Crypt\Password\Bcrypt(); // iterate result, most cross platform way foreach ($result as $row) { if ($bcrypt->verify($this->credential, $row[$this->credentialColumn])) { $row['zend_auth_credential_match'] = 1; $resultIdentities[] = $row; } } } catch (\Exception $e) { throw new Exception\RuntimeException( 'The supplied parameters to DbTable failed to ' . 'produce a valid sql statement, please check table and column names ' . 'for validity.', 0, $e ); } return $resultIdentities; } }3. How to use example.
- Add required namespaces to controller:
use SomeModule\Auth\Adapter\BcryptDbAdapter as AuthAdapter; use Zend\Authentication\AuthenticationService;
- Authenticate user in login action:
$data = $request->getPost(); $dbAdapter = $this->getServiceLocator()->get('Zend\Db\Adapter\Adapter'); $authAdapter = new AuthAdapter($dbAdapter); $authAdapter ->setTableName('users') ->setIdentityColumn('email') ->setCredentialColumn('password'); $authAdapter ->setIdentity(addslashes($data['email'])) ->setCredential($data['password']); // attempt authentication $result = $authAdapter->authenticate(); if (!$result->isValid()) { // Authentication failed } else { $auth = new AuthenticationService(); $storage = $auth->getStorage(); $storage->write($authAdapter->getResultRowObject( null, 'password' )); }
Source code is available on GitHub