User sessions switching in production

I’m using Yii2’s basic template with implemented user login in a website. I followed the instructions in the Yii2 complete guide to achieve the login implementation.

The login works but shows a strange behavior in production wich I’ll explain next.

User A logins from computer A.

User A can navigate in the website with the apropiate menu (which depends on user profile). Everything normal here.

User B logins from computer B.

It doens’t happen all the time, but in ocations there’s a session switch of the user in Computer A, this is, User A suddenly appears as User B just by navigating througt the aplication. This includes the change of the context menu.

After the change, if the user keeps navigating, suddenly may be switched again. So the behaviour is really strange.

I dont know why that happens and if someone can help me I would really apreciate it.

The implementation of the user interface is the next:




class Usuario extends \yii\db\ActiveRecord implements \yii\web\IdentityInterface

{

    /**

     * @inheritdoc

     */

    public static function tableName()

    {

        return 'usuario';

    }


    /**

     * @inheritdoc

     */

    public function rules()

    {

        return [

            [['email', 'perfil_id', 'entidad_id', 'hash'], 'required'],

            [['estatus', 'perfil_id'    ], 'integer'],

            [['email', 'hash', 'auth_key', 'access_token'], 'string', 'max' => 255],

            [['email'], 'unique'],

            [['email'], 'email'],

            [['perfil_id'], 'exist', 'skipOnError' => true, 'targetClass' => Perfil::className(), 'targetAttribute' => ['perfil_id' => 'id']],

        ];

    }


    /**

     * Finds an identity by the given ID.

     *

     * @param string|integer $id the ID to be looked for

     * @return IdentityInterface|null the identity object that matches the given ID.

     */

    public static function findIdentity($id)

    {

        return static::findOne($id);

    }


    /**

     * Finds an identity by the given email.

     *

     * @return IdentityInterface|null the identity object that matches the given ID.

     */

    public static function findByEmail($email)

    {

        return static::find()->where(['email' => $email])->one();

    }

    

    /**

     * Finds an identity by the given token.

     *

     * @param string $token the token to be looked for

     * @return IdentityInterface|null the identity object that matches the given token.

     */

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

    {

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

    }

    

    /**

     * @return int|string current user ID

     */

    public function getId()

    {

        return $this->id;

    }

    

    /**

     * @return string current user auth key

     */

    public function getAuthKey()

    {

        return $this->auth_key;

    }

    

    /**

     * @param string $authKey

     * @return boolean if auth key is valid for current user

     */

    public function validateAuthKey($authKey)

    {

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

    }

    

    public function beforeSave($insert)

    {

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

            if ($this->isNewRecord) {

                $this->auth_key = \Yii::$app->security->generateRandomString();

            }

            return true;

        }

        return false;

    }

    

    public function validarUsuario($password){

        if(Yii::$app->getSecurity()->validatePassword($password, $this->hash)&& $this->estatus == 1){

            return true;

        } else{

            return false;

        }

    }

}



And the configuration like this:




'user' => [

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

            'enableAutoLogin' => false, //Im not using cookies.

        ],



The login form class:




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'],

        ];

    }


    public function attributeLabels()

    {

        return [

            'username' => 'Usuario',

            'password' => 'Contraseña',

        ];

    }


    /**

     * 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->validarUsuario($this->password)) {

                $this->addError($attribute, 'Usuario o contraseña incorrectos.');

            }

        }

    }


    /**

     * 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()

    {

        return Usuario::findByEmail($this->username);

    }



An the LoginController:




 public function actionLogin()

    {

        $this->layout = "small-b";


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

            return $this->redirect(['usuario/main']);

        }


        $model = new LoginForm();

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

            return $this->redirect(['usuario/main']);

        }

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

            'model' => $model,

        ]);

    }



Any help is apreciated.

Hello,

I am facing the same issue in production. Please share if you have any work around.

Thank you.

The default implementation does not have this issue. Based on what you said the login process is not the issue since on login the right user is authenticated. You also said it only happens after you start navigating throughout the application. However you assign roles and or check access is most likely the issue.