[MODULE] Yiiauth

Hybridauth for yii

Demo and info on the official hybridauth page above

[color="#FF0000"]EDIT* Made major updates today, new sql and new instructions. Please read, I’m sorry for inconvience but I realised I had to change the structur to provide more functions.

New are also easy methods to access facebook/twitter api,save/load user sessions

and update user status. [/color]

In short, hybridauth is a library that makes working with auth api’s from diffrent providers alot easier. With the addon it currently has support for 29 providers,facebook,twitter,google,tumblr,myspace etc aswell as any openid server.

[size="5"]Instructions:[/size]

Put hybridauth folder in your root, and if you want to use the same (huge) icons I used put the login_icons dir in your root/images.

Import /yiiauth/social.sql to your database, change prefix if needed.

Put yiiauth folder in protected/modules.

You have to extend application.components.controller to Yiiauth


<?php class Controller extends Yiiauth{...?>

You can then extend Yiiauth/components/yiiauth from CController,RController or whatever you using:)

In your protected/config/main.php’s import array, add ‘application.modules.yiiauth.components.*’,

and add into ‘modules’ array add:


'yiiauth'=>array(

	'userClass'=>'User', //the name of your Userclass

	'config'=>array(

	"base_url" => "http://domain/hybridauth/", 

	"providers" => array ( 

		// openid providers

		"OpenID" => array (

			"enabled" => true

		),

		"Yahoo" => array ( 

			"enabled" => true 

		),

		"AOL"  => array ( 

			"enabled" => true 

		),

	"Google" => array ( 

	"enabled" => true,

	"keys"    => array ("id" => "", "secret" => "" ),

	"scope"   => ""

			),

	"Facebook" => array ( 

	"enabled" => true,

	"keys"    => array ( "id" => "", "secret" => "" ),

// A comma-separated list of permissions you want to request from the user. See the Facebook docs for a full list of available permissions: http://developers.facebook.com/docs/reference/api/permissions.

         "scope"   => "", 

// The display context to show the authentication page. Options are: page, popup, iframe, touch and wap. Read the Facebook docs for more details: http://developers.facebook.com/docs/reference/dialogs#display. Default: page

				"display" => "page" 

			),

			"Twitter" => array ( 

				"enabled" => true,

				"keys"    => array ( "key" => "rPmGEE1Wvsf56BSyQaWXw", "secret" => "V4SK09O0cPOgkabsxR5AruBSNrc0b1tzoBeWkL7ew0" ) 

			),

			// windows live

			"Live" => array ( 

				"enabled" => true,

				"keys"    => array ( "id" => "", "secret" => "" ) 

			),

			"MySpace" => array ( 

				"enabled" => false,

				"keys"    => array ( "key" => "", "secret" => "" ) 

			),

			"LinkedIn" => array ( 

				"enabled" => true,

				"keys"    => array ( "key" => "", "secret" => "" ) 

			),

			"Foursquare" => array (

				"enabled" => false,

				"keys"    => array ( "id" => "", "secret" => "" ) 

			),

		),


		// if you want to enable logging, set 'debug_mode' to true  then provide a writable file by the web server on "debug_file"

		"debug_mode" => false,


		"debug_file" => "",

	),

		)

You have to registrate your app on facebook/twitter etc to recieve a key and a secret.

Set these keys in the config array (how to configure more options can be found on the hybridauth page I linked at thop.

Also dont forget to set your path to hybridauth in that config.

For openID no special key/secret is needed.

To try out on your site there is a loginwidget that can be used simply like this:


	<?php $this->widget('LoginWidget');?>



You can also just browse to domain.com/yiiauth/ to test.

What you will se when you have authenticated is a sample/help view (yiiauth/views/default/profile.php).

Here you can see how to update a users status, use twitter or facebook api calls,store a session in database and retrieve it later

Make sure to look in the source code.

I haven’t added a full user system to this module because I believe most wants to solve this their own way.

But it includes code to create a yii-user,connect them with the provider user etc.

Download (newest)

NOW ON GIT HUB : https://github.com/Sampa/yiiauth

feel free to commit improvements

Example on how to connect with your user system

table for providers:


-- 

-- Structure for table `social`

-- 


DROP TABLE IF EXISTS `social`;

CREATE TABLE IF NOT EXISTS `tbl_social` (

  `id` int(11) NOT NULL AUTO_INCREMENT,

  `yiiuser` int(11) NOT NULL,

  `provider` varchar(50) NOT NULL,

  `provideruser` varchar(255) NOT NULL,

  PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

Use gii to create the the model file.

In Your UserIdentity model (usually protected/components unless u have some user module)




public function hybridauth($username)

	{

		$user=User::model()->find("username = '" . $username . "'");

		if ( $user === null ) 

			$this->errorCode = self::ERROR_USERNAME_INVALID;

		else

		{

			$this->_id = $user->id;

			$this->username = $user->username;

			$this->errorCode = self::ERROR_NONE;

		}

		return $this->errorCode == self::ERROR_NONE;

	}



and for simplicity to make the example the new protected/modules/yiiauth/controllers/DefaultController.php

Its probably bad practise to put all the methods in here but its example demo so…




<?php


class DefaultController extends Controller

{

	public function actionIndex(){

		$this->renderPartial('index');	

	}

	public function actionauthenticatewith( $provider="" ) {   

		require_once( '/hybridauth/Hybrid/Auth.php' );

		$hybridauth_config = $this->hybridAuthConfig();

		$error = false;

		$user_profile = false;

		try{

		// create an instance for Hybridauth with the configuration file path as parameter

			$hybridauth = new Hybrid_Auth( $hybridauth_config );


		// try to authenticate the selected $provider

		if ( isset( $_GET['openid'] ) ){

				$provider = "openid";

				$adapter = $hybridauth->authenticate( $provider,array( "openid_identifier" => $_GET['openid'] ) );

			}else{

				$adapter = $hybridauth->authenticate( $provider );


			}

		// grab the user profile

			$user_profile = $adapter->getUserProfile();

			

		}

		catch( Exception $e ){

			// Display the recived error

			switch( $e->getCode() ){ 

				case 0 : $error = "Unspecified error."; break;

				case 1 : $error = "Hybriauth configuration error."; break;

				case 2 : $error = "Provider not properly configured."; break;

				case 3 : $error = "Unknown or disabled provider."; break;

				case 4 : $error = "Missing provider application credentials."; break;

				case 5 : $error = "Authentification failed. The user has canceled the authentication or the provider refused the connection."; break;

				case 6 : $error = "User profile request failed. Most likely the user is not connected to the provider and he should to authenticate again."; 

					     $adapter->logout(); 

					     break;

				case 7 : $error = "User not connected to the provider."; 

					     $adapter->logout(); 

					     break;

			} 


			// well, basically your should not display this to the end user, just give him a hint and move on..

			$error .= "<br /><br /><b>Original error message:</b> " . $e->getMessage(); 

			$error .= "<hr /><pre>Trace:<br />" . $e->getTraceAsString() . "</pre>";  


		}

		/**$user_profile->identifier; //unique id

		$provider; // the provider name

		$_GET['openid'];//the extra_info

		**/

		

		// workOnUser returns an user object

		$user = $this->workOnUser($provider,$user_profile->identifier); 

		if ( $this->autoLogin($user) ){

			$this->render('profile',

				array(

				'error'=>$error, 

				'provideruser'=>$user_profile,

				'yiiuser'=>$user,

				'provider'=>$provider,	

				) );

			}else{

			$this->render('authenticatewith',array('error'=>$error,'user_profile'=>$user_profile ) );

		}

	} 


	public function workOnUser($provider,$provideruser){

		$social = Social::model()->find("provider='".$provider."' AND provideruser='".$provideruser."'");

		if ( $social ){

			 $user = User::model()->find("id=".$social->yiiuser);

			 return $user;

		}else{

			// we want to create a new user, but since we get no user input the validation rules will cause

			//errors on save to counter this i added 'on'=>'validation' to all my user validation rules

			//example: 	array('username, password', 'required','on'=>'validation'),

			// on normal user registration with user input I use: new User('validation') 

			$user = new User;

			$user->username = $provideruser; 

			

			if ( $user->save() ){ //we get an user id

			//add a social connection between the newly created yii user and the provider user account to avoid double regestrations and enable the same yii user to have many providers associated with it.

				$social = new Social;

				$social->yiiuser = $user->id;

				$social->provider = $provider;

				$social->provideruser = $provideruser;

				if($social->save())

					return $user;

			}

		}

	

	}

	

	public function autoLogin($user) //accepts a user object

	{

	$identity=new UserIdentity($user->username, "");

	$identity->hybridauth($user->username);

	if ( $identity->errorCode == UserIdentity::ERROR_NONE )

		{

			$duration= 3600*24*30; // 30 days

			Yii::app()->user->login($identity,$duration);

			return true;

		}

		else

		{

			echo $identity->errorCode;

			return false;

		}

	

	}

}?>



then create protected/modules/yiiauth/views/default/profile.php





<?php

	if( isset( $error ) ){

		echo  $error;

	}


	echo $yiiuser->id. "<br/>"; // the yii user id

	echo $yiiuser->username."<br/>"; // the yii user name

	echo $provider ."<br/>"; // provider,twitter,fb etc

	var_dump($provideruser); //the object with all info u mby want to use from the provider

?>



Thanks a lot for posting your progress…I’ve been waiting for something like this for a while…I will test this when I refocus my effort on user/registration…

Thank you, My biggest problem now is A) lack of time, B) I developed my user system for one app and its still pretty tight to that app, meaning If I moved it all to another app I would get a shitload of tiny errors like missing variables etc. So I have to clear all this outh.

Otherwise its… very easy to start up actually.

I noticed I had a problem with authorizing thrue facebook, even though other providers worked perfectly fine.

Now, for some reason facebook didnt like some certificate,so I found a solution that worked for me.

in Hybridauth/Hybrid/Providers/Facebook.php

you can find on row 365 an array, curl opts. Add SSL_VERIFYPEER =>false.

public static $CURL_OPTS = array(

CURLOPT_CONNECTTIMEOUT =&gt; 10,


CURLOPT_RETURNTRANSFER =&gt; true,


CURLOPT_TIMEOUT        =&gt; 60,


CURLOPT_USERAGENT      =&gt; 'facebook-php-3.1',


CURLOPT_SSL_VERIFYPEER =&gt; false // &lt;--- THIS I ADDED

);

I updated the method workOnUser in DefaultController

Now if a Yii user is already logged in, the provider is connected to that user.

This way a user can have multiple provider accounts connected to the same yii-user.




	public function workOnUser($provider,$provideruser){

		$social = Social::model()->find("provider='".$provider."' AND provideruser='".$provideruser."'");

		if ( $social ){

			 $user = User::model()->find("id=".$social->yiiuser);

			 return $user;

		}else{ // no user is connected to that provideruser, 

			$social = new Social; // a new relation will be needed

			$social->provider = $provider; // what provider

			$social->provideruser = $provideruser; // the unique user

			

			// if a yii-user is already logged in add the provideruser to that account

			if ( !Yii::app()->user->isGuest ){

				$social->yiiuser = Yii::app()->user->id;	

				$user = User::model()->findByPk(Yii::app()->user->id);

			}else{

			// we want to create a new user

				$user = new User;

				$user->username = $provideruser; 


				if ( $user->save() ){ //we get an user id

					$social->yiiuser = $user->id;

					}

			}

			if($social->save())

				return $user;

		}

	

	}



And sample code to put on the profile view to show the providers that is connected to that user and allow him to connect more:




<h4> By connecting a social provider to your account you can use it to login<h4>

	<?php $socials = Social::model()->findAll('yiiuser='.$model->id);

		 if($socials){

			echo "<h5>You have currently connected your account with:</h5>";

			foreach($socials as $social){

				echo "* <b>".$social->provider."</b><br/>";

			}

		 }

		$this->widget('LoginWidget');//displays the possible providers

	?>



I there an alternative to put it in vendors folder in yii application instead of the root.

Edit* Yes, just use the new path when you use requiere_once()

(like in authenticatewith action in defaultcontroller…)

But I’m working on fixing some stuff to make these things easier

Does this extension provide a way to post updates to these provider networks? E.g. can it be used to allow Facebook status updates or tweets?

Yes,its not hard at all. I’ve done a method for it that will be included in next release…

But now already you can test with $adapter->setUserStatus( ‘foo’ );

in default controller,after successful auth.

Those who has support for status updates is:




$providers = array('facebook', 'twitter', 'identica', 'linkedin', 'qq', 'sina', 'murmur', 'pixnet','plurk');



Are you missing the providers array in module file in the new update or where did you move it.

I put a check for that in the updateStatus method in Yiiauth component (inside the module).

So if you run $this->updateStatus($provider,$status); it will check if $provider is in that array you showed, if it is it will set the user status to $status. So you do not have to worry about that.

The array for providers you would like to use, is set in the config, how to configure it is shown on the hybridauth info page. i strongly recommend to read that:)

How do you download this?

Where is the download link?

For the extension page (it also contains the download link for the current release):

http://www.yiiframework.com/extension/yiiauth/

The second line is error because of the first error, and I dont know why that line would give you an error if the login works, that same Yii::app()->controller->module->config is ran on login to… hmm

Yes…that’s why i think the problem shouldn’t be there…

So weird…

Is that works on you?

Hm, I will test it. I misread your first post, didnt see what method you were using.

I dont have time for it right now, but I will probably do it tomorrow:p

Thanks so much! That’s a great great module! :D

Ah, It didnt work for me either first, I found I had typo.

At approximately line 145




public function updateStatus($provider,$status){

	$this->newAuth();

//Change to

public function updateStatus($provider,$status){

$hybridauth = $this->newAuth();



Then it should work,atleast did so for me:)

I found that typo and had corrected it yesterday…So this is not the problem…

Still give me "Trying to get property of non-object"…

Don’t know why the same method is just not working here…!!!

-.-