Yii2 Login via SQLite - it won't log me in

Hello guys,

first of all: I’m using PHP 5.6.14 and Yii 2.0.6 on a Windows machine and Apache.

I’m pretty frustrated.

I’m using the basic Yii2 template and try to implement User Login, but can’t figure out why it won’t log me in.

The problem is, I have to use an already existing database with a horrible structure:

6820

Screen Shot 2015-11-26 at 15.06.51.png

As you can see, “Alias” = Username and “Password” is a bcrypt hash of the user’s password.

And here is my StudyController.php (excerpt):




<?php


namespace app\controllers;


use Yii;

use yii\web\Controller;

use yii\widgets\ListView;

use yii\data\ActiveDataProvider;

use app\models\Study;

use app\models\StudySearch;

use app\models\Image;

use app\models\User;

use app\models\LoginForm;

use yii\filters\AccessControl;

use yii\filters\VerbFilter;


class StudyController extends Controller {

  public function behaviors() {

    return [

        'access' => [

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

            'only' => ['index', 'show-images', 'logout'],

            'rules' => [

                [

                    'allow' => true, // allow rule

                    'actions' => ['login'], // empty array: deny/allow all

                    'roles' => ['?'], // not authorized / guest

                ],

                [

                    'allow' => true, // allow rule

                    'actions' => ['index', 'show-images', 'logout'],

                    'roles' => ['@'], // logged-in user

                ],

            ],

        ],

        'verbs' => [

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

            'actions' => [

                'logout' => ['post'],

            ],

        ],

    ];

  }


public function actionLogin()

{

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

        return $this->goHome();

        //return $this->redirect('/study/index');

    }


    $model = new LoginForm();

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

        return $this->goHome();

        //return $this->goBack();

    }


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

        'model' => $model,

    ]);

}



And here is my LoginForm.php Model:




<?php


namespace app\models;


use Yii;

use yii\base\Model;

use app\models\User;


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

        }

        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 the User Model which implements the IdentityInterface:




<?php


namespace app\models;


use Yii;

use yii\web\IdentityInterface;

use yii\base\NotSupportedException;


/**

 * This is the model class for table "Config".

 */

class User extends \yii\db\ActiveRecord implements IdentityInterface

{

    public static $userID;

    public static $hash;


    public $authKey;


    public static function tableName()

    {

        return 'Config';

    }


    public static function getDb()

    {

        return Yii::$app->dbConfig;

    }


    public function rules()

    {

        return [

            [['username', 'hash'], 'required'],

            [['username', 'hash'], 'string'],

        ];

    }


    public static function findIdentity($id) {

        $sql = 'SELECT DISTINCT a.Subcategory as id, a.Value as username, b.Value AS hash FROM Config as a, Config as b

                    WHERE

                        a.Category=b.Category AND a.Subcategory=b.Subcategory

                        AND a.Category = 9 AND a.Name = "Alias" and b.Name="Password" AND id = :id';


        $user = static::findBySql($sql, [':id' => $id])->one();

        if(!empty($user)) {

            self::$userID = $user->id;

            self::$hash = $user->hash;

        }


        return (!empty($user)) ? new static($user) : null;

    }


    public static function findByUsername($username) {

        $sql = 'SELECT DISTINCT a.Subcategory as id, a.Value as username, b.Value AS hash FROM Config as a, Config as b

                    WHERE

                        a.Category=b.Category AND a.Subcategory=b.Subcategory

                        AND a.Category = 9 AND a.Name = "Alias" and b.Name="Password" AND username = :username';


        $user = static::findBySql($sql, [':username' => $username])->one();


        if(!empty($user)) {

            self::$userID = $user->id;

            self::$hash = $user->hash;

        }


        return (!empty($user)) ? $user : null;

    }


    public static function validatePassword($password) {

        return Yii::$app->getSecurity()->validatePassword($password, self::$hash);

    }


    public function getId() {

        if(empty(self::$userID)) {

            throw new NotSupportedException('getID ist leer'); // just testing

        }

        else {

            return self::$userID;

        }

    }


    public function setId($id) {

        self::$userID = $id;

    }


    public function getHash() {

        return self::$hash;

    }


    public function setHash($hash) {

        self::$hash = $hash;

    }


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

        throw new NotSupportedException('"findIdentityByAccessToken" is not implemented.');

    } 

    public function getAuthKey() {

        //$this->generateAuthKey();

        return $this->authKey;

    }

    public function validateAuthKey($authKey) {

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

    }


    public function generateAuthKey() {

        $this->authKey = \Yii::$app->getSecurity()->generateRandomString();

        $this->save();

    }


    public function beforeSave($insert)

    {

        if (parent::beforeSave($insert)) {

            if ($this->isNewRecord) {

                //$this->authKey = \Yii::$app->getSecurity()->generateRandomString();

                $this->generateAuthKey();

            }

            return true;

        }

        return false;

    }

}



And last but not least, the Login View:




<?php


/* @var $this yii\web\View */

/* @var $form yii\bootstrap\ActiveForm */

/* @var $model app\models\LoginForm */


use yii\helpers\Html;

use yii\bootstrap\ActiveForm;

use app\models\User;


$this->title = 'Login';

$this->params['breadcrumbs'][] = $this->title;


echo '<pre>';

print_r(Yii::$app->request->post());

echo '</pre>';


echo '<pre>';

print_r(Yii::$app->user->identity);

echo '</pre>';

?>

<div class="site-login">

    <h1><?= Html::encode($this->title) ?></h1>


    <p>Please fill out the following fields to login:</p>


    <?php $form = ActiveForm::begin([

        'id' => 'login-form',

        'options' => ['class' => 'form-horizontal'],

        'fieldConfig' => [

            'template' => "{label}\n<div class=\"col-lg-3\">{input}</div>\n<div class=\"col-lg-8\">{error}</div>",

            'labelOptions' => ['class' => 'col-lg-1 control-label'],

        ],

    ]); ?>


        <?= $form->field($model, 'username') ?>


        <?= $form->field($model, 'password')->passwordInput() ?>


        <?= $form->field($model, 'rememberMe')->checkbox([

            'template' => "<div class=\"col-lg-offset-1 col-lg-3\">{input} {label}</div>\n<div class=\"col-lg-8\">{error}</div>",

        ]) ?>


        <div class="form-group">

            <div class="col-lg-offset-1 col-lg-11">

                <?= Html::submitButton('Login', ['class' => 'btn btn-primary', 'name' => 'login-button']) ?>

            </div>

        </div>


    <?php ActiveForm::end(); ?>

</div>



When I open the Login Form and insert a valid username and password, it brings me back to the Login Form. Looked into Yii Logs and here is the output:

6821

yii-output.png

As you can see, it obviously logged me in. But still, I can’t go to another page like /index (it automatically redirects me back to /login).

The cookie “_identity” is there and my own database queries in the User.php Model seem to work fine (otherwise the screenshot wouldn’t show the right userID from the database).

Here’s the user components part of my config:




'components' => [

    'user' => [

        'identityClass' => 'app\models\User',   

        'enableAutoLogin' => true,

        'enableSession' => true,

        'loginUrl' => ['study/login'],

    ],



I’m not even sure anymore if there’s a bug in Yii or if I’m doing something wrong… Of course I tested the basic template with a “normal” user table (in MySQL) and it worked without a problem.

Thank you very much.

Shayan