Problem with login

Hello friends

I need create a simple login using data base, so I changed my User model and LoginForm model, I don’t receive error message but I can’t login, I receive the message:

Incorrect user or password.

in my table i have this fields and values to test:

username: bb

password: 123

auth_key: 123

I put the values directly in table, I don’t create a action to input data in this moment.

I’m using this tutorial:

http://www.bsourcecode.com/yiiframework2/yii-2-user-login-from-database/#change-sitecontroller

Whats my error?

This is my model:




<?php

namespace app\models;


use Yii;

use yii\base\NotSupportedException;

use yii\db\ActiveRecord;

use yii\helpers\Security;

use yii\web\IdentityInterface;


class User extends \yii\db\ActiveRecord implements IdentityInterface

{

    public static function tableName()

    {

        return 'tb_users';

    }

 

    public function rules()

    {

        return [

            [['name', 'username', 'password', 'email', 'level', 'created_at', 'id_user','auth_key'], 'required'],

            [['created_at', 'updated_at'], 'safe'],

            [['modified', 'status', 'id_user'], 'integer'],

            [['name', 'username', 'password', 'email', 'level','password_reset_token'], 'string', 'max' => 250]

        ];

    }


    public function attributeLabels()

    {

        return [

            'id' => 'ID',

            'name' => 'Name',

            'username' => 'User',

            'password' => 'Password',

            'email' => 'Email',

            'level' => 'Level',

            'created_at' => 'Created At',

            'updated_at' => 'Updated At',

            'modified' => 'Modified',

            'status' => 'Status',

            'id_user' => 'Id User',

        ];

    }


    public function getAuthKey() {

        return $this->auth_key;

    }


    public function getId() {

        return $this->getPrimaryKey();

    }


    public function validateAuthKey($authKey) {

        return $this->getAuthKey() === $authKey;

    }


    public static function findIdentity($id) {

        return static::findOne($id);

    }


    public static function findIdentityByAccessToken($token, $type = null) {

        return static::findOne(['access_token' => $token]);

    }


    public static function findByUsername($username)

    {

        return static::findOne(['username' => $username]);

    }

    

    public static function findByPasswordResetToken($token)

    {

        $expire = \Yii::$app->params['user.passwordResetTokenExpire'];

        $parts = explode('_', $token);

        $timestamp = (int) end($parts);

        if ($timestamp + $expire < time()) {

            // token expired

            return null;

        }

 

        return static::findOne([

            'password_reset_token' => $token

        ]);

    }

    

    public function validatePassword($password)

    {

        return $this->password === sha1($password);

    }

    

    public function setPassword($password)

    {

        $this->password_hash = Security::generatePasswordHash($password);

    }

    

    public function generateAuthKey()

    {

        $this->auth_key = Security::generateRandomKey();

    }


    public function generatePasswordResetToken()

    {

        $this->password_reset_token = Security::generateRandomKey() . '_' . time();

    }

    

    public function removePasswordResetToken()

    {

        $this->password_reset_token = null;

    }

}



My LoginForm:




<?php

namespace app\models;


use Yii;

use yii\base\Model;


class LoginForm extends Model

{

    public $username;

    public $password;

    public $rememberMe = true;


    private $_user = false;


    public function rules()

    {

        return [

            // user and password are both required

            [['username', 'password'], 'required'],

            // rememberMe must be a boolean value

            ['rememberMe', 'boolean'],

            // password is validated by validatePassword()

            ['password', 'validatePassword'],

        ];

    }

    public function validatePassword($attribute, $params)

    {

        if (!$this->hasErrors()) {

            $username = $this->getUser();


            if (!$username || !$username->validatePassword($this->password)) {

                $this->addError($attribute, 'Incorrect user or password.');

            }

        }

    }


    public function login()

    {

        if ($this->validate()) {

            return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600*24*30 : 0);

        } else {

            return false;

        }

    }


    public function getUser()

    {

        if ($this->_user === false) {

            $this->_user = User::findByUsername($this->username);

        }


        return $this->_user;

    }

}



My SiteController




<?php


namespace app\controllers;


use Yii;

use yii\filters\AccessControl;

use yii\web\Controller;

use yii\filters\VerbFilter;

use app\models\LoginForm;

use app\models\ContactForm;


class SiteController extends Controller

{

    public $layout='adm/default';

    

    public function behaviors()

    {

        return [

            'access' => [

                'class' => AccessControl::className(),

                'only' => ['logout'],

                'rules' => [

                    [

                        'actions' => ['logout'],

                        'allow' => true,

                        'roles' => ['@'],

                    ],

                ],

            ],

            'verbs' => [

                'class' => VerbFilter::className(),

                'actions' => [

                    'logout' => ['post'],

                ],

            ],

        ];

    }


    public function actions()

    {

        return [

            'error' => [

                'class' => 'yii\web\ErrorAction',

            ],

            'captcha' => [

                'class' => 'yii\captcha\CaptchaAction',

                'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,

            ],

        ];

    }


    public function actionIndex()

    {

        //return $this->render('index');

        return $this->redirect('index.php?r=site/login');

    }


    public function actionLogin()

    {

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

            return $this->goHome();

        }


        $model = new LoginForm();

        if ($model->load(Yii::$app->request->post()) && $model->login()) {

            return $this->goBack();

        } else {

            return $this->render('login', [

                'model' => $model,

            ]);

        }

    }


    public function actionLogout()

    {

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


        return $this->goHome();

    }


    public function actionContact()

    {

        $model = new ContactForm();

        if ($model->load(Yii::$app->request->post()) && $model->contact(Yii::$app->params['adminEmail'])) {

            Yii::$app->session->setFlash('contactFormSubmitted');


            return $this->refresh();

        } else {

            return $this->render('contact', [

                'model' => $model,

            ]);

        }

    }


    public function actionAbout()

    {

        return $this->render('about');

    }

}



I found the problem, on this function:

public function validatePassword($password)

{


   return &#036;this-&gt;password === sha1(&#036;password);


}

this line especific:

    return &#036;this-&gt;password === sha1(&#036;password);

there is this command "shall". I change the line:

public function validatePassword($password)

{


    return &#036;this-&gt;password === &#036;password;


}

Now the login is ok, but I need encrypt the password, What’s the better way to encrypt password and stored in my database?

Why I need the field auth_key on my table? what should I store in this field?

I found this tutorial:

http://www.yiiframework.com/doc-2.0/guide-security-passwords.html

And i stored the password using this:

$users->password = Yii::$app->getSecurity()->generatePasswordHash( $_POST[‘User’][‘password’], $cost = 13);

This stored ok. But when I need compare the password send by user to login I use this:

public function validatePassword($password)

{  


    return &#036;this-&gt;password === Yii::&#036;app-&gt;getSecurity()-&gt;validatePassword(&#036;password);


}

But I have this error:

PHP Warning – yii\base\ErrorException

Missing argument 2 for yii\base\Security::validatePassword(), called in /Users/Alexandre/web_projects/ibless/medicine_work/models/User.php on line 106 and defined

This is the line 106:

return $this->password === Yii::$app->getSecurity()->validatePassword($password);

Why don’t you just use advanced template ? It has login system working out of the box ( it use database ). Or you can use any of mine improved ones given in my signature.

If you need to use basic template you can just move code from advanced one there.

The basic template is good to my app, but I need use database to login, I need only fix the problem:

public function validatePassword($password)

{

return $this->password === Yii::$app->getSecurity()->validatePassword($password);

}

But I have this error:

PHP Warning – yii\base\ErrorException

Missing argument 2 for yii\base\Security::validatePassword(), called in /Users/Alexandre/web_projects/ibless/medicine_work/models/User.php on line 106 and defined

This is the line 106:

return $this->password === Yii::$app->getSecurity()->validatePassword($password);

So… add the second function argument?

Look up the api for that method and see what it wants. I’m guessing a method that validates a password would compare a submitted value with a stored value and see if they match.

I fix the problem, I do this to save:

$users->password = Yii::$app->getSecurity()->generatePasswordHash( $_POST[‘User’][‘password’]);

and in User I do this to validate:

public function validatePassword($password)

{  


    return Yii::&#036;app-&gt;getSecurity()-&gt;validatePassword(&#036;password, &#036;this-&gt;password);


}

is there a better way?

You should really try this. You will have everything working out of the box.

But if you really want to go with your solution, this may help:

In your User model put these two methods:




/**

 * Validates password.

 *

 * @param  string $password

 * @return bool

 * 

 * @throws \yii\base\InvalidConfigException

 */

public function validatePassword($password)

{

    return Yii::$app->security->validatePassword($password, $this->password);

}




and




/**

 * Generates password hash from password and sets it to the model.

 *

 * @param  string $password

 * 

 * @throws \yii\base\Exception

 * @throws \yii\base\InvalidConfigException

 */

public function setPassword($password)

{

    $this->password_hash = Yii::$app->security->generatePasswordHash($password);

}



When you are signin up users you should use this setPassword setter method, for example like this:




$user->setPassword($this->password);



When logging in, validate password with:




/**

 * Validates the password.

 * This method serves as the inline validation for password.

 *

 * @param string $attribute The attribute currently being validated.

 * @param array  $params    The additional name-value pairs given in the rule.

 */

public function validatePassword($attribute, $params)

{

    if (!$this->hasErrors()) 

    {

        $user = $this->getUser();


        if (!$user || !$user->validatePassword($this->password)) 

        {

            $this->addError($attribute, 'Incorrect username or password.');

        }

    }

}



and login with:




/**

 * Logs in a user using the provided username and password.

 *

 * @return boolean Whether the user is logged in successfully.

 */

public function login()

{

    if ($this->validate()) 

    {

        return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600 * 24 * 30 : 0);

    } 

    else 

    {

        return false;

    }

}



EDIT: I have updated first method since you are calling password: "password" and not "password_hash".

VEry good. Thanks Nenad, i put this in my code, very good.