André Castro André Castro - 6 days ago 8
PHP Question

Yii2 Basic template - How to login from mysql database

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']));
}
}

Answer

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.

Comments