Making Zend_Auth more “Object Oriented”


Recently Giorgio Sironi wrote a post on Zend_Auth. When I saw the title, I was expecting something along the lines of most of his posts, which have been discussing many OO topics. The content was rather disappointing, and I’ll tell you why.

Especially coming from Giorgio, who strikes me as an OO purist, and a big fan of Misko Hevery, the content was rather disappointing. The big problem with Zend_Auth, is that it is not Object Oriented…or at least not the way it’s depicted in the documentation.

Let’s take a classic procedural app, like…I don’t know…Wordpress.

The wordpress API has a function wp_authenticate_username_password, which will authenticate a user, with a given username and password. So, if you had an app which you wanted to connect with WordPress (or maybe write some kind of extension or plugin), you can easily make use of this API. It’s very easy to understand, and there’s nothing inherently wrong with it.

Let’s translate this to Zend_Auth. Or to be more accurate, to Zend_Auth_Adapter_Interface:

public function authenticateAction() {
    //Set up adapter
    $adapter->setIdentity($identity);
    $adapter->setCredential($credential);
    $result = $this->adapter->authenticate();
    //Do other stuff
}

Look’s good right? We’re using an object (Zend_Auth_Adapter_Interface), in an object (LoginController), and returning an object (Zend_Auth_Result). What can be more “Object Oriented” about that?

For a long time this smelled to me, and I couldn’t stand looking at my auth controller. I knew there had to be a better way. So after a lot of thought, pondering, reading, and inspiration, this is what I’ve come with.

The first thing to notice is that all we’ve done was call bunch of methods. These could have easily been static methods, or even global functions like in WordPress’s API. The second sin here, is all these calls make our controller nice and fat. To make matters worse, it makes it hard to reuse this authentication logic somewhere else. Imagine if you were writing a CMS, and somebody wanted to write an extension, using your API (try authenticating a user using Expression Engine‘s “API”).

What did we really want to do though? Authenticate a user of course.

How about something like this?

public function authenticateAction($user = null) {
     if ($user === null) {
          //somehow get the user, probably from a form submission...
     }
     $result = $user->authenticate($authenticationService);

     if ($result->isValid()) {
         $user->login($authenticationService);
     }
}

Here we are delegating our business to logic to the…um…business layer. There are other advantages here, though. The user class doesn’t have to spill his beans to the controller, in keeping with the principle of tell don’t ask.
So what are the bits and pieces here?
The first is obvious…the user class. That just needs a reference to an authenticator. So what is an authenticator? It could be as simple as passing in an instance of Zend_Auth_Adapter_Interface.
But I like to go one level more abstract, and create my own interface for authentication. My default implementation will be a ZendAuthenticator. To make things simple, my implementation will have a hard dependency on Zend_Auth_Adapter_DbTable, and not on the interface for the adapter. I have a couple of reasons for this: 90% of all web apps authenticate a database. The chances of them switching to something else, are not high. Certainly not mine.
Also, in general I don’t like the Zend_Auth_Adapter_Interface. It seems to me that it violates one of Misko’s rules that injectables can depend on injectables, and newables can depend on newables, but the twain shall not mix.
So if my understanding of that rule is correct, $adapter->setIdentity($thisvarisanewable), would be a violation of the rule. And indeed, you can see that to switch adapters would be a big pain. Each adapter is required to be “setup” before calling its authenticate method, and they have wildly different APIs. (Of course, I’ve been trying to think all day how they can all be unified better, and I appreciate that it’s not an easy thing. So let’s just keep it simple (ok, not that simple)).
So my interface looks something like this:

interface Authenticator {
    /* @returns Zend_Auth_Result */
    public function authenticate($username, $password);
    public function login($identity);
}

I split up login and identity, because it entirely desirable at some point to log in a user without having to authenticate him (think “log in as user” for an admin).

(I’ve been back and forth on whether these should really be two different classes, since there are two responsibilities here, if anybody has some recommendations.)

My implementation looks something like this:

class ZendAuthenticator implements IAuthenticator {
	private $adapter;

	public function __construct(Zend_Auth_Adapter_DbTable $adapter) {
		$this->adapter = $adapter;
	}

	public function authenticate($identity,$credential) {
		$this->adapter->setIdentity($identity);
		$this->adapter->setCredential($credential);

		return $this->adapter->authenticate();
	}

	public function login($identity) {
		Zend_Auth::getInstance()->getStorage()->write($identity);
		return Zend_Auth::getInstance()->getIdentity();
	}
}

(Another point to think about here: ignoring Zend_Auth completely, and just using Zend_Session_Namespace. I’m not sure exactly what Zend_Auth is gaining me here. It seems like the real gain here is from the adapter.)

Now my controller doesn’t smell as bad, and is much more of a pleasure to look at.

,

  1. No comments yet.
(will not be published)
  1. No trackbacks yet.