Bonjour à tous,

Je souhaietrais faire en sorte que lorsqu'un utilisateur reset son mot de passe, qu'il oubligé de le changer.
Pourcela j'ai créé un champs dans ma table 'passwordrst'.
Quand il est à 1, il doit changer son mot de passe après qu'il se soit authentifié.

Dans AppController j'ai ceci (qui se trouve dans la fonction beforeFilter)

// Quand on n'est pas dans profil/prefix, soit la vu public
if(!isset($this->request->params'prefix'])){
            parent::beforeFilter();
            $this->Auth->allow();
        }else{  
// Quand on est authentifié et dans /admin/... ou /member/ 
    if($this->Auth->user('passwordrst')){
        $this->redirect(array('controller'=>'users','action'=>'edit','member'=>true));
        $this->Session->setFlash(__('Vous devez changer vtre mot de passe'),'notif',array('type'=>'warning'));
    }
}

Dans le cas, du else, il va controller si le champs est à 1, si oui, il le dirige vers son profile. Ainsi il ne pourra pas aller ailleurs avant qu'il ait changer son mot de passe. Bien entendu apres avoir changé son mot de passe, le champs 'passwordrst' passe à 0.

Mais voilà, cette redirect

$this->redirect(array('controller'=>'users','action'=>'edit','member'=>true));

me retourne ce message d'erreur

The page isn't redirecting properly

Je me demande si c'est parceque la page n'a pas encore été chargée?
J'ai aussi essayé dans la fonction afterFilter.

Je me demande alors ou devrais-je mettre ce code?

Milles mercis

6 réponses


Bonjour.
Il faut que tu changes la façon de faire.
Au lieu de faire un champ pour le reset du password, tu fais un champ active pour le compte et un champ token.
Lorsque l'utilisateur veut reset son mot de passe, tu passes le champ active à 0 et tu envoi un token à l'adresse email de l'utilisateur.
Ensuite l'utilisateur clique sur le lien contenant le token, qui le dirige sur une fonction que tu auras créée au préalable, bien sur, et la fonction lui permettra de se réattribuer un mot de passe et une fois fait, tu passes le champ active à 1 et tu l'authentifies par exemple via

$this->Auth->login($user'User']);

Il te faut bien sur penser à mettre

'scope' => array('User.active' => 1)

dans ton composant Auth dans l' AppController , de cette manière si l'utilisateur reset son mot de passe, il reçoit un email avec un lien pour changer son mot de passe et tant qu'il n'aura pas changé son mot de passe, il ne pourra pas se connecter.
Ce qui t'évites de faire des manipulations supplémentaires dans des beforeFilter ou autre.
Pour info, quand tu fais ton

if($this->Auth->user('passwordrst'))

tu ne fais que vérifier si la valeur existe, mais ça ne contrôle pas qu'elle est sa valeur.
Il te faudrait plutôt faire

if($this->Auth->user('passwordrst') == 1)

.
Pour terminer, le

parent::beforeFilter()

soit tu le met dès le début après l'appel de la fonction beforeFilter ou avant la fermeture de la fonction, exemple :

public function beforeFilter(){
    parent::beforeFilter();
    /* reste du code */
}

ou

public function beforeFilter(){
    /* ton code */
    return parent::beforeFilter();
}

Super, je te remercie pour ces infos. Je vais m'y pencher dessus plus tard.

Hello, merci pour ta réponse

tu passes le champ active à 0 et tu envoi un token à l'adresse email de l'utilisateur.
J'ai deja un champs active et token pour l'activatiuon d'un compte. Je n'aimerais pas utiliser cette solution car si je desactive un compte, par exemple, j'exclu un membre, il va pouvoir le réactiver. C'est pourquoi j'ai fais un champs 'passwordrst' qui est a 1 ou 0.

J'ai fait un poeu différamment en suivi ta proposition

  1. L'utilisateur entre son email pour réseté son mot de pass
  2. Il recoit une e-mail avec son nom d'utilisateur, un mot de pass temporaire , et un lien (avec un token) pour changer de mot passe
  3. J'ai créé une action ou l'utilisateur sera rediriglé. C'est action va comparer son nom d'utilisateur et le token, si la l'utilisateur correspond au token, il pourra changer son mot de passe
  4. Une fois sur cette page (pour changer de mot de passe, il entre son nom d'utilisateur, son e-mail, le mot de passe temporaire et son nouveau mot de passe
  5. Apres l'envoi du formulaire, le syteme controle encore si l'username, le mot de passe temporaire et l'e-mail correspondent avec l'enregistrement dans la base de donnée
  6. Si tout passe, son nouveau mot de passe est enregistré

J'aimaintenant un dernier problème lié à ca. Comment je peux comparer les mot de passe?
Quand l'utilisateur s'enregistre, le mot de passe est haché comme ceci, dans mon model

function beforeSave($options = array()){
        // Si
        if(!empty($this->data'User']'password'])){
            // Encrypt password
            $this->data'User']'password'] = AuthComponent::password($this->data'User']'password']);
            //$this->data'User']'password'] = Security::hash($this->data'User']'password']);
            return true;    
        }
// return true;
    }

le problème c'est quenad je fais ceci

$d'user'] = $this->User->find('first',array(
            'conditions'=>array(
                'username'=>$username,
                'token'=>$token
                )
            ));
        $user = current($d);
debug($user'User']'password']);

le debug me retour 5 étoiles, et le mot de passe dans la base de donnée à 42 carateres!!

Y-a-t-il une méthode pour comparer des mots de passe?

Milles mercis

Tu as hashé ton mot de passe donc c'est normal qu'il fasse 42 caractères en base. C'est aussi normal que tu n'aies pas le résultat en entier dans le debug, c'est une sécurité. Tu ne vas pas pouvoir comparer tes mots de passe car il est crypté. Il faudrait le faire avant ton beforeSave().

J'ai trouvé. je vais posté ma solution quand j'aurai résolu mon dernier binz

Voilà, suis content ca marche bien. Le problème que j'avais encore, c'est que lorsque l'utilisateur a resete son mot de passe, je ne veux pas qu'il puisse s'authentifier comme usuellement. Il doit d'abord changer son mot de passe.
Pour cela, j'ai rajouter le chanps passwordrst ici:

class AppController extends Controller {
    public $helpers = array('Html','Text','Form','Session','Date','Cache','Subcategories','Image.Image','Mathcaptcha');
    public $components = array(
        'Acl',
        'Auth' => array(
             // For the ACL
            'authorize' => array(
                'Actions' => array('actionPath' => 'controllers')
            ),
            'authError' => 'Pensiez-vous réellement que vous étiez autorisés à voir cela ?',
            // Mets des condition au niveau de la validation d'authentificate
            // Contient l'ensemble des methode d'authentification
            'authenticate' => array(
                // Mehtode Form est utilisée
                'Form' => array(
                    // Defini les paramêtre scope. Ici défini que le compte doit est actif
                    'scope'=> array(
                        'User.active' =>1,
                        'User.passwordrst' =>0
                        )
                )
            )
        ), 
        'Session',
        'Ctrl'
    );

Si l'tilisateur reset son mot de passe, le champs passwordrst passe a 1. Quans il est changer ce champs passe à 0.

Pour la solution à mon problème j'ai fais comme ceci en suivant l'idée de latak11 (encore merci). Que pensez vous de mon code?
Es-ce que je peux faire mieux ou plus propre? Dans tous les cas ca marche, mais etant encore un novice dans CakePHP, votre d'avis d'expert me serait très intéressant :o)
Ainsi, si je veux banir un utilisateur, je n'ai juste a agir indépendemment sur le field 'active'

/**
    * When user request a new password
    **/
    function forgottenpassword(){
        if($this->request->is('post')){
            $v = current($this->request->data);
            // Check if the count associate to the e-mail is active
            $user = $this->User->find('first',array(
                'conditions'=> array(
                    'email'=> $v'email'],
                    'active' => 1
                ))
            );
            // If not
            if(empty($user)){
                $this->Session->setFlash(__("Cet e-mail n'existe pas"),'notif',array('type'=>'danger'));
            }else{
                // Generate new password
                $newPass = substr(md5(uniqid(rand(), true)), 8, 8);
                // Generate a token
                $token = substr(md5(uniqid(rand(), true)), 16, 16);
                //Set the DB row at user ID
                $this->User->id = $user'User']'id'];
                // Save new password, the haching is done in the controller at beforeSave()
                $this->User->saveField('password',$newPass);
                //Change passwordrst field status
                $this->User->saveField('passwordrst',1);
                // Save token
                $this->User->saveField('token',$token);
                // Send e-mail
                App::uses('CakeEmail','Network/Email');
                $mail = new CakeEmail();
                $mail->from($this->Session->read('Site.email'))
                    ->to($user'User']'email'])
                    ->subject($this->Session->read('Site.name').' - '.__('Nouveau mot de passe'))
                    ->emailFormat('both')
                    ->template('forgottenpassword')
                    ->viewVars(array('username'=>$user'User']'username'],'pw'=>$newPass,'token'=>$token))
                    // The URL is define ine the view forgottenpassword
                    ->send();
                $this->Session->setFlash(__('Votre mot de passe temporaire vous a été envoyé'),'notif');
            }
        }
    }
    /**
    * When user click on the received mail to reset it password
    **/
    function resetpassword($username,$token){
        // Check if the username and the password match to a row
        $d'user'] = $this->User->find('first',array(
            'conditions'=>array(
                'username'=>$username,
                'token'=>$token
                )
            ));
        // We are going to use the user ID from $user
        $user = current($d);
        // If yes
        if(!empty($user)){
            // GET Post
            if($this->request->is('post')){
                // Save in a var
                $data = $this->request->data'User'];
                // User fill up a form with temp password and new password. He has to enter his username, email and password
                // Now, it check if username, email and password match to the user id field
                $ok = $this->User->find('first',array(
                'conditions'=>array(
                    'User.id'=>$user'User']'id'], // Compare ID
                    'username'=>$data'username'],
                    'email'=>$data'email'],
                    'password'=>AuthComponent::password($data'password']) // Compare password
                    )
                ));
                $ok = current($ok);
                // IF result matches
                if(!empty($ok)){
                    // Select the row DB
                    $this->User->id = $ok'id'];
                    // Replace the Temp passsword with the new
                    $this->User->saveField('password',$data'newpassword']);
                    // Change the passwordrst field status
                    $this->User->saveField('passwordrst',0);
                    // Notify User
                    $this->Session->setFlash(__("Le mot de passe a été changé"),'notif');
                }else{

                    $this->Session->setFlash(__("Les informations fournies ne correspondent à aucun compte"),'notif',array('type'=>'danger'));
                }
            }
        }else{
            $this->Session->setFlash(__("Il n'est plus possible d'initier le mot de passe"),'notif',array('type'=>'danger'));
        }
    }