0
votes

I tried to implement the User Model and LoginForm Model in Yii basic template to validate user logins. I created a database and connected to it. The database as a table user and fields called username, password, authKey, and acessToken populated with values. Extended the User Model from ActiveRecord and implemented \yii\web\IdentityInterface in order to make the in-built Yii2 functions do their job. Also written this method:

public static function tableName() { return 'user'; }

Every time I try to login it throws -> username or password incorrect, from the validatepassword() in LoginForm Model.

Here is my code:

LoginForm Model:

<?php

namespace app\models;

use Yii;
use yii\base\Model;

/**
 * LoginForm is the model behind the login form.
 */
class LoginForm extends Model
{
    public $username;
    public $password;
    public $rememberMe = true;

    private $_user = false;

    /**
     * @return array the validation rules.
     */
    public function rules()
    {
        return [
            // username and password are both required
            [['username', 'password'], 'required'],
            // rememberMe must be a boolean value
            ['rememberMe', 'boolean'],
            // password is validated by validatePassword()
            ['password', 'validatePassword'],
        ];
    }

    /**
     * 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.');
            }
        }
    }

    /**
     * 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;
        }
    }

    /**
     * Finds user by [[username]]
     *
     * @return User|null
     */
    public function getUser()
    {
        if ($this->_user === false) {
            $this->_user = User::findByUsername($this->username);
        }

        return $this->_user;
    }
}

…and here is my User.php Model:

<?php

namespace app\models;

use yii\db\ActiveRecord;

class User extends ActiveRecord implements \yii\web\IdentityInterface
{
    public $id;
    public $username;
    public $password;
    public $authKey;
    public $accessToken;

    public static function tableName() { return 'user'; }

       /**
     * @inheritdoc
     */
    public static function findIdentity($id) {
        $user = self::find()
                ->where([
                    "id" => $id
                ])
                ->one();
        if (!count($user)) {
            return null;
        }
        return new static($user);
    }

    /**
     * @inheritdoc
     */
    public static function findIdentityByAccessToken($token, $userType = null) {

        $user = self::find()
                ->where(["accessToken" => $token])
                ->one();
        if (!count($user)) {
            return null;
        }
        return new static($user);
    }

    /**
     * Finds user by username
     *
     * @param  string      $username
     * @return static|null
     */
    public static function findByUsername($username) {
        $user = self::find()
                ->where([
                    "username" => $username
                ])
                ->one();
        if (!count($user)) {
            return null;
        }
        return new static($user);
    }

    /**
     * @inheritdoc
     */
    public function getId() {
        return $this->id;
    }

    /**
     * @inheritdoc
     */
    public function getAuthKey() {
        return $this->authKey;
    }

    /**
     * @inheritdoc
     */
    public function validateAuthKey($authKey) {
        return $this->authKey === $authKey;
    }

    /**
     * Validates password
     *
     * @param  string  $password password to validate
     * @return boolean if password provided is valid for current user
     */
    public function validatePassword($password) {
        return $this->password === $password;
    }

}

I don't know what else should i do, perhaps it has a problem in validating the password or find the username, in Yii2 debug it shows that is proper connected to the mysql database.

Don't messed with the siteController actionLogin() because it is equal to the advanced template and i think it correct to stay that way.

In short, the below function keeps throwing "Incorrect username or password.":

public function validatePassword($attribute, $params)
{
    if (!$this->hasErrors()) {
        $user = $this->getUser();

        if (!$user || !$user->validatePassword($this->password)) {
            $this->addError($attribute, 'Incorrect username or password.');
        }
    }
}

I don't want to give up, but I'm considering go back to the old Yii1.xx. There I could easily query the database and make a good login system working.

I spent almost 72 hours with this login problem and no solution solved it for the basic Yii2 template.

I don't want to use static $users that came as default in the package.

EDIT 2
siteController.php

<?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;
use yii\helpers\url;

class SiteController extends Controller
{
    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');
    }

    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->redirect(Url::toRoute(['contacto/index'])); 
        } 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->redirect(Url::toRoute(['contacto/create2']));
        }
    }

    public function actionAbout()
    {
        return $this->render('about');
    }

    public function actionSkills()
    {
        return $this->render('skills');
    }

    public function actionPortfolio()
    {
        return $this->render('portfolio');
    }

    // tradução do site
    public function beforeAction($action) {
        if (Yii::$app->session->has('lang')) {
            Yii::$app->language = Yii::$app->session->get('lang');
        } else {
            Yii::$app->language = 'us';
        }
        return parent::beforeAction($action);
    }

    public function actionLangus(){  
        Yii::$app->session->set('lang', 'us'); //or $_GET['lang']
        return $this->redirect(Url::toRoute(['site/index']));   
    }

    public function actionLangpt(){  
        Yii::$app->session->set('lang', 'pt'); //or $_GET['lang']
        return $this->redirect(Url::toRoute(['site/index']));
    }
}
1
Can you post your controller and view as well?Brett
HI BRETT, thank's for trying to help. I've posted the siteController. The login view is as came in original file and stackoverflow gives error when trying to paste it.André Castro
I had a look your code again, I don't use active record but it appears you are comparing the user submitted password to the hashed password that comes from the database?Brett
Humm!! And where did you see that comparison? It is important to me to understand how things work. Thanks.André Castro
Well in your rules method you make a call to validatePassword which then calls validatePassword from your user model and passes it the password as the user entered it; and then you do a comparison in there between that password and what I believe is the password taken from the users table - you would like need to use the validatePassword method: yiiframework.com/doc-2.0/…Brett

1 Answers

3
votes

1) Stop creating duplicate questions
2) remove the public declarations of variables bellow.

class User extends ActiveRecord implements \yii\web\IdentityInterface
{
public $id;
public $username;
public $password;
public $authKey;
public $accessToken;

$user->password will be empty because of this. Instead of using a magic method to get the values you are actually declaring them... they will always be empty when you use them.