Integrated authorization of users that supports the several services

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:

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

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".
![]() |
![]() |
|
Vote for this post
Bring it to the Main Page |
||
![]() |
![]() |
Comments
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!
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 :)
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.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 : [email protected]
But still facebook and twitter logout not working
include(LoginForm.php): failed to open stream: No such file or directory
Any ideas?
can you help me ??
Leave a Reply