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