Yes It Is!
Raiting:
0

Integrated authorization of users that supports the several services


imageWhen I had been implementing a project on Yii framework, I got the task to make the registration and authorization of users through the different services (Google, Facebook, Twitter, etc).

This task has two ways of solution:
• Using an authorization service, such as Loginza;
• Implementing an authorization of functions independently for each service.

Here are benefits to use the authorization service:
1. Simplicity and speed of installation;
2. There is no need to learn the details of authorization through each provider.

However, a self-authorization has other advantages:
1. Full control over the process of authorization: what we will write in the authorization window of provider, what information we will receive and so on;
2. Ability to change appearance of the authorization widget in compliance with a design of the website;
3. Ability to invoke methods of API when we authorize over OAuth, if the service provider provides them;
4. There is less dependency from the different services and it is more reliable.

I chose the second option, because I did not have the ready extensions for yii, and I was wondering how such authorization system looks like from the inside. It was part of a module to manage the users at first, but later this functional has been extracted in a separate extension, which can be used easily in any project.

1. Requirements for the authorization system


I have complied with the following principles in the extension design:
1. Necessity to abstract from the details of authorization over different types of services, using the adapters for each service.
2. Getting a unique ID authorization, this can be used for a user registration into an application.
3. Extension possibility of the standard classes of authorization to obtain additional data about the user.
4. Ability to work with API of social networks by extending the class of authorization that is required by a service.
5. Ability to customize the list of services that are supported by a website and to redefine an appearance of the authorization widget. Ability to use the popup window to authorize without closing an application.

2. EAuth extension


EAuth extension is a result of implementation of the above requirements.
The extension includes:
• Component that contains the secondary functions.
• Widget that displays a list of services in the form of icons and allowing the authorization in the popup window.
• Base classes to add the services that are based on OpenID or OAuth.
• Ready classes to authorize through Google, Yandex, Twitter, Facebook, Vkontakte and Mail.ru.

3. Installation


First, we should download and unpack the extension in `protected/extensions/eauth`.

3.1 Dependencies


The extension uses loid and EOAuth to work with OpenID and OAuth, respectively. These extensions should be downloaded and placed in the directory of `protected/extensions`.

3.2 Settings


We need to add in the configuration `main.php`:
'import'=>array(
'ext.eoauth.*',
'ext.eoauth.lib.*',
'ext.lightopenid.*',
'ext.eauth.services.*',
),

'components'=>array(
'loid' => array(
'class' => 'ext.lightopenid.loid',
),
'eauth' => array(
'class' => 'ext.eauth.EAuth',
'popup' => true, // Use the popup window instead of redirecting.
'services' => array( // You can change the providers and their classes.
'google' => array(
'class' => 'GoogleOpenIDService',
),
'yandex' => array(
'class' => 'YandexOpenIDService',
),
'twitter' => array(
'class' => 'TwitterOAuthService',
'key' => '...',
'secret' => '...',
),
'facebook' => array(
'class' => 'FacebookOAuthService',
'client_id' => '...',
'client_secret' => '...',
),
'vkontakte' => array(
'class' => 'VKontakteOAuthService',
'client_id' => '...',
'client_secret' => '...',
),
'mailru' => array(
'class' => 'MailruOAuthService',
'client_id' => '...',
'client_secret' => '...',
),
),
),
),

Extension has only two parameters: popup and services. Parameter popup is responsible for the use of the authorization for popup window instead of redirecting to the website of provider. The parameter services is a list of providers that are supported by our application. We can specify its own class for each provider based on the base class of provider. We must register an application with the proper provider in order to get the keys to OAuth providers.

4. Usage


As an example, let us take a standard application Yii that was generated by a command ` yiic webapp create `, and add the authorization through Google and Yandex (we will not use OAuth providers, we do not bother with keys). We can view a demo.

4.1 UserIdentity


First, we create a class ServiceUserIdentity that is responsible for the login with our expansion. Class code:
<?php
class ServiceUserIdentity extends UserIdentity {
const ERROR_NOT_AUTHENTICATED = 3;

/**
* @var EAuthServiceBase the authorization service instance.
*/
protected $service;

/**
* Constructor.
* @param EAuthServiceBase $service the authorization service instance.
*/
public function __construct($service) {
$this->service = $service;
}

/**
* Authenticates a user based on {@link username}.
* This method is required by {@link IUserIdentity}.
* @return boolean whether authentication succeeds.
*/
public function authenticate() {
if ($this->service->isAuthenticated) {
$this->username = $this->service->getAttribute('name');
$this->setState('id', $this->service->id);
$this->setState('name', $this->username);
$this->setState('service', $this->service->serviceName);
$this->errorCode = self::ERROR_NONE;
}
else {
$this->errorCode = self::ERROR_NOT_AUTHENTICATED;
}
return !$this->errorCode;
}
}

The standard classes of providers provide two attributes: id and name. In addition, each provider has its own identifier, which is in the property of serviceName. In a class of ServiceUserIdentity we save attributes in the session (and in cookie) of the current user.

4.2 Editing of SiteContoller


The second step is to change the action of ` site/login `. We add the following code to the top of steps:
public function actionLogin () {
public function actionLogin() {
$service = Yii::app()->request->getQuery('service');
if (isset($service)) {
$authIdentity = Yii::app()->eauth->getIdentity($service);
$authIdentity->redirectUrl = Yii::app()->user->returnUrl;
$authIdentity->cancelUrl = $this->createAbsoluteUrl('site/login');

if ($authIdentity->authenticate()) {
$identity = new ServiceUserIdentity($authIdentity);
// Successful login
if ($identity->authenticate()) {
Yii::app()->user->login($identity);

// Special redirect with closing popup window
$authIdentity->redirect();
}
else {
// Close popup window and redirect to cancelUrl
$authIdentity->cancel();
}
}

// Something went wrong, redirect to login page
$this->redirect(array('site/login'));
}

// then goes standard code...
}

First, we check the availability of the variable $ _GET ['service']. If this variable exists, then create an instance of the provider and set up a way to divert and cancel the authorization.Then call the `$ authIdentity-> authenticate ()`, which is doing for us the magic. Methods for `$ authIdentity-> redirect ();` and `$ authIdentity-> cancel ();` necessary for the proper closing of popup window, if it is used.

4.3 Editing of form ` protected/views/site/login.php `


We need to add a few lines after the main form to use a standard widget:
<h2>Do you already have an account on one of these sites? Click the logo to log in with it here:</h2>
<?php Yii::app()->eauth->renderWidget(); ?>

We can copy the file to change an appearance of the widget: `protected/extensions/eauth/views/auth.php` to `[theme_name]/views/EAuthWidget/auth.php`.

4.4 The result


We can open our website and go to the webpage Login after all of the above actions. There will appear authorization service windows after a standard authorization form:

image

When we click, for example, the icon will open Google popup window:

image

If the user confirms the authorization for this application, then a user will be authorized and redirected to the webpage redirectUrl (an example, Yii::app()->user->returnUrl). If the user clicks No, thanks, then popup window will be closed.

Conclusion


That is all, the authorization system is ready for use. What else we can do with the extension:
• Receive the additional information about the user by extending the classes of providers. We can see an example in the demo when we authorize through Vkontakte;
• Integrate the extension with yii-user. In general, in order to register a user we need just to add in a table {{users}} two fields: service and identity. The first field is the name of the authorization service (property serviceName). The second is a unique user ID for this service (property id);
• Use extension to work with API of social networks.

Links

Download EAuth
Demo
Yii Framework
OpenID
OAuth
OAuth 2.0
loid extension
EOAuth extension

UPDATE: I added an expansion loid in a paragraph "3.2 Settings".
Killer 13 december 2011, 14:37
Vote for this post
Bring it to the Main Page
 

Comments

0 bobrofax March 29, 2012, 9:03
Thank you for an excellent article!

It all works perfectly. I just have one problem with the Twitter service. When calling Yii::app()->user->login($identity) this returns null. However Yii::app()->user->name does contain the Twitter username so I am a bit confused. Calling Yii::app()->user->isGuest returns true which is unexpected after successful authentication.

Any ideas?

Thanks!
0 bobrofax March 29, 2012, 10:04
Solved.

The authenticate() method in ServiceUserIdentity was not explicitly setting the identity id so I added:

$this->id = $this->service->id;
Thanks again for your work :)
0 KlauS March 29, 2012, 11:05
You are fast. ;) Thank for your answer here. I think it may help someone in the future.
0 Apollo April 13, 2012, 18:04
Hey man....You have a nice post here but Im having some little issues with these :
1) 4.1 UserIdentity
You have created the class but where Im I supposed to create the class?In the controllers or where ?


2) 4.2 Editing of SiteContoller

public function actionLogin () {
public function actionLogin() {
$service = Yii::app()->request->getQuery('service');
if (isset($service)) {
$authIdentity = Yii::app()->eauth->getIdentity($service);
$authIdentity->redirectUrl = Yii::app()->user->returnUrl;
$authIdentity->cancelUrl = $this->createAbsoluteUrl('site/login');

if ($authIdentity->authenticate()) {
$identity = new ServiceUserIdentity($authIdentity);
// Successful login
if ($identity->authenticate()) {
Yii::app()->user->login($identity);

// Special redirect with closing popup window
$authIdentity->redirect();
}
else {
// Close popup window and redirect to cancelUrl
$authIdentity->cancel();
}
}

// Something went wrong, redirect to login page
$this->redirect(array('site/login'));
}

// then goes standard code...
}

why the two public function actionLogin () and I suppose that the code is supposed to go in the site controller's action login,Is it after the autogenerated code or where? please elaborate... Im trying to implement this but It has refused.
0 annada April 25, 2012, 7:31
I have follow the same step .

1)added in the configuration `main.php`:
2)follows the steps .

but I am not able to see the final result . could you explain or guide me to my email id : mrannada@gmail.com
0 dbk May 23, 2012, 22:54
Very nice extension. I am able to get it working perfectly with a new fresh installation webapp. However, I am trying to use this with Yii User. When I click on the login links I am getting a 404 login not found. Am I missing something? Thanks!
0 Danc June 9, 2012, 17:20
how about to get Attribute (email) from Facebook OAuthService
0 jeewe November 7, 2012, 5:13
Thanks for sharing this API.

But still facebook and twitter logout not working
0 jnerd404 February 15, 2013, 8:24
I get the error below after adding the code for the widget in SiteController:

include(LoginForm.php): failed to open stream: No such file or directory

Any ideas?
0 kleop February 18, 2013, 21:36
You have problems with your sources. Try to find "LoginForm.php" by yourself and place it to the same directory where all of your sources are located
0 jnerd404 February 20, 2013, 0:41
I was able to solve this with a Yii::import('application.models.LoginForm'). Now, the problem is UserIdentity. I don't get this problem. Isn't Yii supposed to locate the classes since they have already been loaded in main.php?
0 wayaba March 22, 2013, 13:40
Does anybody tried to work with APIs once authenticated with this extension?
0 Dustin September 3, 2013, 10:40
Why am I having this error Property "EAuth.service" is read only. I followed what is exactly in the tutorial and even changed the property of the file but still no luck. Please help me. I've been stucked with this problems for 3 days now.
0 donny April 29, 2014, 4:17
i've some problem to integrate EAuth with User Extensions, everything is ok... but when i click link always show 404 error.
can you help me ??
0 Killer April 30, 2014, 12:08
waht link is in your url bar when you are getting 404 error?

Leave a Reply

B
I
U
S
Help
Avaible tags
  • <b>...</b>highlighting important text on the page in bold
  • <i>..</i>highlighting important text on the page in italic
  • <u>...</u>allocated with tag <u> text shownas underlined
  • <s>...</s>allocated with tag <s> text shown as strikethrough
  • <sup>...</sup>, <sub>...</sub>text in the tag <sup> appears as a superscript, <sub> - subscript
  • <blockquote>...</blockquote>For  highlight citation, use the tag <blockquote>
  • <code lang="lang">...</code>highlighting the program code (supported by bash, cpp, cs, css, xml, html, java, javascript, lisp, lua, php, perl, python, ruby, sql, scala, text)
  • <a href="http://...">...</a>link, specify the desired Internet address in the href attribute
  • <img src="http://..." alt="text" />specify the full path of image in the src attribute