Ma come funziona l'autenticazione su yii?

Ciao a tutti.

Dopo le prime 48 ore di nebbia e depressione nel cercare di imparare questo framework,

oggi inizio a comprenderlo e mi sembra un buon prodotto.

Tuttavia non riesco proprio a capire come funzoni l’autenticazione e spero di trovare aiuto.

Vado a spiegare il problema:

Quando si crea un applicazione demo,

yii crea 2 utenze

admin admin

demo demo

i vari controller che si vanno a sviluppare possono naturalmente interagire con le utenze. Fin qui… fantastico!

Bene, ora voglio andare ad implementare questo sistema di autenticazione, poggiandomi su una tabella del db.

Allora cosa faccio? Mi installo srbac

Ma quelle utenze iniziali admin e demo rimangono.

Allora non capisco più cos’è che non ho capito.

Devo forse usare un altro widget?

P.s.

srbac funziona male, mi ha svuotato la tabella di prova che avevo creato e non l’ha ricostruita con tutti i campi

Prima di fare altro, leggi questa guida:

http://www.yiiframework.com/doc/guide/1.1/en/topics.auth

il framework sa solo che un utente ha username, password e si deve autenticare. Ma l’autenticazione spetta a te. gli utenti demo demo ed admin admin stanno in un array, con quella guida, ti viene spiegato come estendere UserIdentity e recuperare username e password da database anzichè da array. Non solo, ti spiega anche dove implementare il metodo di autenticazione.

Dopo aver letto quella guida le mie parole e la logica di yii ti saranno subito chiare. Garantito =).

L’autenticazione l’ho più o meno capita, ma continua a sfuggirmi qualcosa.

Nel frattempo ho anche provato ad installare rigths

e mi son ritrovato con il tuo stesso problema di quando avevi provato tu

solo che io facendo come hai fatto tu non ho risolto del tutto.

Anche se da rigths creo un nuovo utente, yii continua a farmi autenticare solo con admin e demo

e tra l’altro nella tabella user, l’utente admin ha una password differente da admin

eppure quando faccio l’autenticazione, yii riconosce solo

admin admin

demo demo

e non riesco proprio a capire come cavolo faccio a dirgli: usa il sistema di autenticazione tramite db

io pensavo di averglielo ben spiegato scrivendo:




 'components'=>array( 

...


		'authManager'=>array(

            'class'=>'RDbAuthManager',

		),

...



Ti do un altro aiutino: controlla bene la classe UserIdentity. Se noti, la prima riga fa una query sul model User e controlla che la username sia esattamente come quella che hai inserito tu.




class UserIdentity extends CUserIdentity

{

    private $_id;

    public function authenticate()

    {

        $record=User::model()->findByAttributes(array('username'=>$this->username));

        if($record===null)

            $this->errorCode=self::ERROR_USERNAME_INVALID;

        else if($record->password!==md5($this->password))

            $this->errorCode=self::ERROR_PASSWORD_INVALID;

        else

        {

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

            $this->setState('title', $record->title);

            $this->errorCode=self::ERROR_NONE;

        }

        return !$this->errorCode;

    }

 

    public function getId()

    {

        return $this->_id;

    }

}



Adesso mi sbottono =).

Questa è l’autenticazione presente in UserIdentity non appena viene creata una applicazione con yii. Gli utenti sono demo ed admin. Quando tu fai login con uno dei due capiti nella catena di if:


if(!isset($users[$this->username]))

questo if è falso perchè l’utente che hai indicato esiste …


if($users[$this->username]!==$this->password)

anche questo è falso perchè anche la password è corretta quindi …


$this->errorCode=self::ERROR_NONE;

quindi non ci sono errori di autenticazione

ecco tutto il codice




	public function authenticate()

	{

		$users=array(

			// username => password

			'demo'=>'demo',

			'admin'=>'admin',

		);

		if(!isset($users[$this->username]))

			$this->errorCode=self::ERROR_USERNAME_INVALID;

		else if($users[$this->username]!==$this->password)

			$this->errorCode=self::ERROR_PASSWORD_INVALID;

		else

			$this->errorCode=self::ERROR_NONE;

		return !$this->errorCode;

	}



Beh, tu non vuoi che i tuoi utenti siano




		$users=array(

			// username => password

			'demo'=>'demo',

			'admin'=>'admin',

		);

ma vuoi pescarli dal database. Quindi io mi aspetto che crei una tabella User, il suo model, e che modifichi UserIdentity base con quello che ti ho postato poco fa. In questo modo, potrai fare login utilizzando i dati presenti nel database e non più quelli che si trovano nell’array.

Se mi sbottono un altro po’ prendo freddo. E se mi ammalo poi è un casino. Penso di meritarmi un più =).

Probabilmente ieri sera ero molto stanco. Ora è tutto chiaro.

Posto per completezza l’intera unit /protected/components/UserIdentity.php che gestisce l’autenticazione via db





<?php


/**

 * UserIdentity represents the data needed to identity a user.

 * It contains the authentication method that checks if the provided

 * data can identity the user.

 */

class UserIdentity extends CUserIdentity

{

	/**

     * Questo è lo spezzone di codice base per far autenticare

     * i soli utenti admin e demo

     * la funzione @return boolean (true = utente autenticato).

	public function authenticate()

	{

		$users=array(

			// username => password

			'demo'=>'demo',

			'admin'=>'admin',

		);

		if(!isset($users[$this->username]))

			$this->errorCode=self::ERROR_USERNAME_INVALID;

		else if($users[$this->username]!==$this->password)

			$this->errorCode=self::ERROR_PASSWORD_INVALID;

		else

			$this->errorCode=self::ERROR_NONE;

		return !$this->errorCode;

	}

     */

	

	

	/**

     * Questo è lo spezzone di codice riscritto per implementare

     * l'autenticazione tramite db appoggiandosi alla classe User

     * la funzione @return boolean (true = utente autenticato).

     */

    private $_id;

    public function authenticate()

    {

    	//cerco l'utente $this->username nella classe User

        $record=User::model()->findByAttributes(array('username'=>$this->username));

        //e non lo trovo

        if($record===null)

            $this->errorCode=self::ERROR_USERNAME_INVALID;

        //Se la password è incorretta (fa un controllo con la psw cifrata nel db in md5)

        //else if($record->password!==md5($this->password))

        else if($record->password!==$this->password)

        	$this->errorCode=self::ERROR_PASSWORD_INVALID;

        //Se l'utente è autenticato

        else

        {

        	//mi segno l'id dell'utente autenticato

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

            /* se voglio mi posso memorizzare in sessione altri dati dell'utente loggato

            $this->setState('title', $record->title);

            $this->setState('cognome', $record->cognome);

            Qui ci sono maggiori informazioni in merito per estendere la classe User

            http://www.yiiframework.com/forum/index.php?/topic/22225-yiiapp-user-name-extender

            */            

            $this->errorCode=self::ERROR_NONE; //nessun errore, tutto ok!

        }

        return !$this->errorCode; //true = do il conseso a loggare l'utente

    }

 

    public function getId()

    {

        return $this->_id;

    }

}

?>



A qualcuno potrebbe esser d’aiuto anche questa piccola applicazione didattica per approfondire la costruzione di un form che implementa login e registrazione

sto provando questa soluzione che avete proposto ma mi sono trovato in degli errori.

ho messo in UserIdentity.php


private $_id;

	

	 public function authenticate()

    {

        $record=tblUtenti::model()->findByAttributes(array('username'=>$this->username));

        if($record===null)

            $this->errorCode=self::ERROR_USERNAME_INVALID;

        else if($record->password!==md5($this->password))

            $this->errorCode=self::ERROR_PASSWORD_INVALID;

        else

        {

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

          //  $this->setState('title', $record->title);

            $this->errorCode=self::ERROR_NONE;

        }

        

        return !$this->errorCode;

    }

 

    public function getId()

    {

        return $this->_id;

    }



nel controller, gli passo in chiaro user e pass (pass md5)




if (isset($_POST['TblUtenti'])) {

			$identity = new UserIdentity("pippo", "04dac8afe0ca501587bad66f6b5ce5ad");

		if ($identity -> authenticate()) {

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

			$this -> render('welcome', array('model' => $model));

		}else{

			echo $identity -> errorMessage;

		}



facendo però login mi ritorna sempre nella stessa pagina, ovvero non mi entra nell’if$identity -> authenticate()

:huh:

Prova a cambiare questa riga


else if($record->password!==md5($this->password))

così


else if($record->password!==$this->password)

bravo! Che svista!

grazie :P

Volevo mantenere la possibilità di ricevere le notifiche sulle regole ( non può essere bianco, password non corretta).

Allora ho scritto questo nel cotnroller.




public function actionAutenticazione() {

		$model = new TblUtenti;

		if (isset($_POST['TblUtenti'])) {


			$identity = new UserIdentity($_POST['TblUtenti']['username'], $_POST['TblUtenti']['password']);

			if ($identity -> authenticate()) {

				echo "OK";

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

				$this -> render('welcome', array('model' => $model));

			} else {

				//echo"NO";

				$model -> attributes = $_POST['TblUtenti'];

				$model -> validate() == false;

				$this -> render('autenticazione', array('model' => $model));


			}


		} else {

			Yii::app() -> user -> logout();

			$this -> render('autenticazione', array('model' => $model));

		}

	}



ho forzato a false il validate, non sono riuscito a trovare un "metodo" migliore…

ogni volta che rientro nella pagina del Login, anche se sono loggato, mi fa rieffettuare il Login

è normale? è dovuta alla random key, che viene rigenerata?

questo metodo è un metodo speciale che mi fa raggiungere user da ovunque voglio ( credo di aver capito) ma il metodo login, che si aspetta un argomento, dove si trova?

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

Ciao a tutti,

sto cercando di implementare quanto spiegato qui e su http://www.yiiframework.com/doc/guide/1.1/en/topics.auth.

Andando su site/login ora non ho più l’errore che riguardava l’autenticazione tramite admin e demo, ma sembra che l’accesso al DB funzioni.

L’unico problema è che appena effettuo il login, la mia applicazione accede a user/admin e ovviamente riscontro un "Error 403

You are not authorized to perform this action".

Come posso risolvere?

Devi aggiungere il permesso nel tuo controller. Se il controller in questione è SiteController, dentro dovresti trovare/aggiungere il seguente metodo. Nel tuo caso specifico, dovresti controllare UserController.




    public function accessRules() {

        return array(

            array('allow', // allow all users to perform 'index' and 'view' actions

                'actions' => array('index', 'view'),

                'users' => array('*'),

            ),

            array('allow', // allow authenticated user to perform 'create' and 'update' actions

                'actions' => array('create', 'update'),

                'users' => array('@'),

            ),

            array('allow', // allow admin user to perform 'admin' and 'delete' actions

                'actions' => array('admin', 'delete''),

                'users' => array('NOME_DEL_TUO_UTENTE', 'admin'),

            ),

            array('deny', // deny all users

                'users' => array('*'),

            ),

        );

    }



Se preferisci dare accesso a tutti gli utenti autenticati, invece, puoi usare questa configurazione:




    public function accessRules() {

        return array(

            array('allow', // allow all users to perform 'index' and 'view' actions

                'actions' => array('index', 'view'),

                'users' => array('*'),

            ),

            array('allow', // allow authenticated user to perform 'create' and 'update' actions

                'actions' => array('create', 'update','admin', 'delete'),

                'users' => array('@'),

            ),

            array('deny', // deny all users

                'users' => array('*'),

            ),

        );

    }



Scusa se ne approfitto, ma non riesco comunque a capire perché dopo il login, mi reindirizza a user/admin quando voglio semplicemente che, dopo il login, l’utente rimanga nel sito o che comunque non vada ad effettuare azioni dell’admin che ovviamente gli sono offlimits.

Incolla qui il codice UserController::actionLogin(); Forse li c’è la risposta a questo problema.

Hmm…

io ho creato il Model "User" con relativa tabella e le varie operazioni CRUD.

Il login me lo effettua SiteController::actionLogin() che rimane quello dell’applicazione di default di Yii:




public function actionLogin()

	{

		$model=new LoginForm;


		// if it is ajax validation request

		if(isset($_POST['ajax']) && $_POST['ajax']==='login-form')

		{

			echo CActiveForm::validate($model);

			Yii::app()->end();

		}


		// collect user input data

		if(isset($_POST['LoginForm']))

		{

			$model->attributes=$_POST['LoginForm'];

			// validate user input and redirect to the previous page if valid

			if($model->validate() && $model->login())

				$this->redirect(Yii::app()->user->returnUrl);

		}

		// display the login form

		$this->render('login',array('model'=>$model));

	}



L’errore mi viene dato quando viene effettuato il login con autenticazione da DB (con le opportune modifiche a UserIdentity che hai spiegato qui sopra.

Sono certo che il login vada a buon fine perché quando lo sbaglio appositamente, mi chiede di reinserire la password correttamente.

Al momento sto cercando di risolvere questo problema.

In teoria il codice che dice di andare alla pagina di admin è questo:




$this->redirect(Yii::app()->user->returnUrl);



Se qui ci metti …




$this->redirect('site/index');



… in teoria dovresti tornare alla home.

Ma yii si basa sui cookie per capire se l’utente è loggato o meno?

Se si, quali cookie crea e che valori assegna?

Grazie mille sensorario; in effetti era semplice e intuibile :)

Una domanda più tecnica: ora che abbiamo modificato UserIdentity per il login tramite il model User e che quindi ha dati scelti da noi (user, password, indirizzo, cap, telefono, etc…), come posso recuperare queste informazioni?

L’oggetto “user” è sempre utilizzabile come prima?

Per quanto riguarda invece l’admin?

Come si fa a collegare l’admin logico della vecchia versione di UserIdentity con un utente del DB (o comunque, impostare un utente admin)?

Ho appena scritto un nuovo Topic in questo forum per spiegare come si estende il componente user. Ti consiglio di darci un occhio così potrai scrivere:




Yii::app()->user->name // questo va già 

Yii::app()->user->password // mmm eviterei

Yii::app()->user->indirizzo

Yii::app()->user->cap 

Yii::app()->user->telefono 

Yii::app()->user->etc