Logging in Users using Doctrine and Zend_Auth
January 26th, 2010Here’s the second part of my Doctrine / Zend_Auth example. In 15 minutes, we create a logout, login and protected area that’s reliant on the ZC_Auth_Adapter adapter we created in last week’s video. Notice how there’s no code in the IndexController exposing the authentication implementation,
Grab a copy of the project or browse the repository.
Also, a big thank you to ServerGrove for extending their support of Zendcasts for January. ServerGrove specializes in Zend Framework hosting and they’ve offered a 10% rebate on hosting with coupon code “zc”. If you’re looking for a host, be sure to check them out (referral). They’ve also added an additional coupon for “Mini Hosting” plans, get $2 off by using code “zcmini”.

Nice & easy implementation
Very cool…. ^^
Thanks for the clear and straight forward tutorials.
I find login is required for most controllers. For these cases the hasIdentity check and redirect can be moved from each action to a single instance in the predispatch function for that controller.
For instance:
public function preDispatch()
{
if (!$this->Zend_Auth::getInstance()->hasIdentity()) {
$this->_redirect(‘/’);
}
}
Of course it wouldn’t work so well for the controller that actually handles login and needs the unauthenticated users to reach some page to enter there credentials.
Hi Jon,
first off all I want to say a huge thanks for zendcasts!!
And I have a small question for you. Is there any way how to set logging in this way: “Every time doctrine connects to the database write how long that request took.” I mean is it possible to set this thing globaly?
thanks for answer.. Milan
hey Milan,
I haven’t experimented with this personally, but I would look into Doctrine’s plugin architecture and specifically it’s profiler:
http://www.doctrine-project.org/documentation/manual/1_0/hu/component-overview:profiler
Hey David, you’re quite right about the authentication being in the wrong place! In a typical application, I would have the login code redirect to a different module in my app that’s protected. I would then use a Controller_Plugin to check the module and compare the module with the Zend_Auth identity to see if the person is allowed to access the module. This example strips out those layers in favour of showing the simplicity of the actual authentication code.
I’ve just finished building my first ap with zend and wish I’d found your site before I started building it. I reckon I’ll go through the videos from the first one you made onwards to try and learn zend properly.
Cheers
Most of the time, I found myself needing authentication on a controller by controller basis. so my approach is to write myself a custom MyApp_Controller_Action class by extending the default Zend_Controller_Action. In this custom controller action class, I basically do the Zend_Auth check and other common things that you may want to do for your authentication protected controllers. Then I’ll have my auth required controllers extend MyApp_Controller_Action, and those public controllers (ie, login, index, etc) extend the default Zend_Action_Controller.
Not sure if this is a good approach, but there you go.
Hi, a small question. I implement this in my project but using this when the user has identity in my Controller
if(Zend_Auth::getInstance()->hasIdentity()) {
//$this->_forward(‘access’);
//Instead of use forward I want to use
$this->_redirect(‘/admin/access’);
//to redirect to another
//module/controller
}
but when I use the code above I get this error:
Zend_Session::start() – /opt/lampp/htdocs/library_1.9/Zend/Loader.php(Line:164): Error #2 fopen(/opt/lampp/htdocs/transpanish.biz/application/models/AdministradorTable.php) [function.fopen]: failed to open stream: No existe el fichero รณ directorio Array
It seems that it want to write on AdministradorTable.php This file doesn’t exist only Administrador.php in my Models directory. What is happening ?
Thank you and great videos I am learning a lot.
Hi martin,
I would double check your Doctrine configuration. It sounds like for some reason there’s been a flag set for generating table classes in Doctrine in addition to the models. You’ll want to disable that and regenerate the base classes. You can also compare your configuration with the one on zendcasts’ google code site.
Hi Jon, everything seem to be ok, but I saw when I comment this line in Zend_Auth::getInstance()->clearIdentity(); in my logout method redirection take place without problems. The same when use if I comment (!Zend_Auth::getInstance()->hasIdentity())
to controll access in my controller. Zend_Auth is trying to write something in a wrong place. I am using routers so maybe the problem is there. I ‘ll check it. Thank you.
Hi Joe, I followed your instructions step by step, but I also received the error which is similar to martin’s when trying to execute “Zend_Auth::getInstance()->clearIdentity()” and “!Zend_Auth::getInstance()->hasIdentity()”
The error says:
Message: Zend_Session::start() – D:\Program Files\WAMP\www\zf\library\Zend\Loader.php(Line:181): Error #2 fopen(D:\Program Files\WAMP\www\zf\application/models/UserTable.php) [function.fopen]: failed to open stream: No such file or directory
Has anyone found a solution?
Hi Jon,
Thanks for putting up wonderful tutorials.
I;ve got 2 questions:
1. I’ve noticed that you said Doctrine 2.0 would support multiple ‘modules’ (default/admin etc). Doctrine 2.0 Alpha has been released. Can I expect this feature in alpha release. Are you planning for a tutorial on that
?
2. How can I use 2 databases with Doctrine?
Thanks.
Hi there,
1. I’m going to wait till the dust settles and an “official” approach to doing this is published.
2. I would look at Doctrine’s connection documentation: http://www.doctrine-project.org/documentation/manual/1_1/e+n/connections
Hope that helps!
Hi Dave. I couldn’t solve this. It seems that Zend_Auth loose their data across the pages. I don’t know how to storage this data like I have been using with Zend_Auth_Adapter_DbTable because those methods doesn’t exist for Zend_Auth_Adapter_Interface or I have been doing bad calls of this methods
I use this approach (http://blog.elinkmedia.net.au/2010/01/24/zf-authentication-using-doctrine/comment-page-1/#comment-40) and it works ok, maybe you could make a plugin to use it like Jon’s did in his tutorial.
@martin and @dave, if you are interested, I made another post, which shows how I introduced a auth service class to take away the auth logic from the controller. you may want to checkout.
I’ll try to give Jon’s sample app a shot later today and let you know if I have similar issues.
@jon I downloaded the sample app, and tried to make a _redirect to a different controller after auth. for some reason, it seems like the identity does not persist. Also, there’s an error in the schema yaml file from the goolecode. i think the last line should be “name: string()” instead.
@marsbomber Good catch! I got my YAML files confused.
in terms of the _redirect, you can also try the redirector: http://framework.zend.com/manual/en/zend.controller.actionhelpers.html#zend.controller.actionhelpers.redirector
@jon tried the redirector in indexcontroller, $this->_redirector->gotoUrl(‘/abc’);
in my abc controller,
if (!Zend_Auth::getInstance()->hasIdentity()) {
var_dump(Zend_Auth::getInstance()->getIdentity()->toArray());
}
else {
echo “NO GOOD”;
}
i still have no good printed.
@martin, I downloaded the source code and compared each file, and the cause of the issue I found was actually in the bootstrap file:
$manager->setAttribute(Doctrine::ATTR_AUTOLOAD_TABLE_CLASSES, true);
As soon as I removed the line above, it didn’t give me any error of Zend_Sessions.
Hope it helps.
Genius @dave !! That’s right, I probe it and everything is ok and I realized that @jon’s googlecode does not appear that line, I don’t know where I got it. Everything ok, big thanks for you, @jon and @jim, greetings.
Hi,
As usual excellent tutorial
Do you think is it the right approach
to get auth either with username or with email
public static function authenticate($usernameOrEmail, $password)
{
try{
if(false !== filter_var($usernameOrEmail, FILTER_VALIDATE_EMAIL)){
$user = self::findOneByEmail($usernameOrEmail);
}
else{
$user = self::findOneByUsername($usernameOrEmail);
}
}
catch(Exception $e){
throw new Exception(self::DB_TROUBLES);
}
if (false !== $user){
if ($user->password == $password){
if($user->status === ‘1′){
return $user;
}
throw new Exception(self::WRONG_STATUS);
}
throw new Exception(self::WRONG_PW);
}
throw new Exception(self::NOT_FOUND);
}
Bye.
PS
My 5 cents to avoid storing the password
in session
public function authenticate()
{
try
{
$this->user = Model_User::authenticate($this->usernameOrEmail, $this->password);
}
catch (Exception $e)
{
if ($e->getMessage() == Model_User::DB_TROUBLES){
return $this->result(Zend_Auth_Result::FAILURE, self::DB_TROUBLES_MESSAGE);
}
if ($e->getMessage() == Model_User::NOT_FOUND){
return $this->result(Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND, self::NOT_FOUND_MESSAGE);
}
if ($e->getMessage() == Model_User::WRONG_PW){
return $this->result(Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID, self::BAD_PW_MESSAGE);
}
if ($e->getMessage() == Model_User::WRONG_STATUS){
return $this->result(Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID, self::BAD_STATUS_MESSAGE);
}
}
$this->user->password = null;
return $this->result(Zend_Auth_Result::SUCCESS);
}
You never know
Great set, i was finally about to merge the series on zend_db, zend_acl and zend_auth to come up with a decent demo:)
How do you get your var_dump output to be formatted so nicely?
@shaded:
I could be wrong, but i think that formatting is the xdebug extension doing it’s thing.
I’ve got xdebug installed and when I do a var_dump my output gets automatically formatted. Just like a stack trace when an exception has occurred.
If you are using apc chache on top of public/index.php you have to put:
function shutdown()
{
Zend_Session::writeClose(true);
}
register_shutdown_function(’shutdown’);
otherwise it’ll crash.
here is more about that:
http://stackoverflow.com/questions/1364750/opcode-apc-xcache-zend-doctrine-and-autoloaders