André Castro André Castro - 6 months ago 139
SQL Question

Yii2 step-by-step guide on login from table in MySQL

I'm begining to make the first steps in Yii2. So far, I was able to write an application and connect a table in a database to it, just like I learned to do in Yii1.

The table is

contacts
and the form in my create view sends the data to the database with no problems.

The problem is that I only can login using Admin/Admin or demo/demo in the static user model that comes built-in in Yii2.

In Yii1.xx i manage to validate login from a table in database using COMPONENTS/useridentity, just like this (I used a table named
utilizador
, with fields
id
,
utilizador
and
password
):

class UserIdentity extends CUserIdentity
{

public function authenticate() {
$conexao=Yii::app()->db;
$consulta="select utilizador,password from utilizador ";
$consulta.="where utilizador='".$this->username."' and ";
$consulta.="password='".$this->password."'";

$resultado=$conexao->createCommand($consulta)->query();

$resultado->bindColumn(1,$this->username);
$resultado->bindColumn(2,$this->password);

while($resultado->read()!==false){
$this->errorCode=self::ERROR_NONE;
return !$this->errorCode;
}
}

}


With Yii2 I have read a lot of tutorials, including one in Stack Overflow but none of them enlighten me on the procedure to login users with username and password from a MySQL database. Yii2 don't have components/useridentity.php and I don't know where to start and what is the proper code to make it work overriding the static user model that comes out of the box.

I also have tried an extension Yii2-user, read the PDF guide but didn't understand how to call the route's from the vendor folder in my controllers. Made several tries but all failed.

Can someone teach me how to validate login from database in Yii2, preferentially without using an extension?

Edit

I read this tutorial in Stack Overflow
Yii Framework 2.0 Login With User Database

And also studied the PDF from Yii2-user extension, but don't know what to do with following part and next ones of the pdf. It speaks about routes, but i don't know how to work with them:

2.3.1 Show users
Route /user/admin/index shows a list of registered users. You will be able to see a lot of useful information such as registration time and ip address, confirmation and block status, etc.

I have also read this:
http://www.yiiframework.com/doc-2.0/yii-web-user.html
but I don't think it has the steps to resolve my problem.

EDIT 2

I tried to implement the User Model and LoginForm Model in Yii basic template to validate user logins. Created a database and coneected to it. The database as a table user and fields username, password, authKey, 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 wrrited the 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:




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

}


Any ideas ?? -> Thanks...

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 touched in the siteController actionLogin() because it is equal to the advanced template and i think it is better to stay that way.

EDIT 3 -> 4 HOURS messing with the models code, putting in pratice every solution i read and it still throws "Incorrect username or password." from:

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.

Answer

Yii2 advanced app comes by default with a working example of the login part from the DB (I see the basic ones uses a static username and password). You do not have to install anything extra, just look at the code. Install the advanced app and take a look at the frontend.

In short SiteController uses LoginModel for validation then uses the login() of the LoginModel to login the User model to the User component.

If you do not want to use the User model, just create your own model and use that one. You do not want to use the default User component, just create your own. It is quite easy to do.

Edit: mate, 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;

You are telling Yii to ignore what is in the database.