How to login from different tables in Yii2 basic application? - yii2

i have two table : Admin and Employees.
with different columns name.
how to create database login system for this scenario.
i am using Yii2 basic application.
i don't know how to deal with this problem.

One way out of this situation is using abstractions
E.g:
abstract class User extends ActiveRecord{
// abstract method that should overrided child classes
abstract function tableName();
}
class Admin extends User {
function tableName() { return 'admin'; }
}
class Employee extends User {
function tableName() { return 'employee'; }
}
But, it's depended on your exact situation. Also you can use setTableName() method for override only table name in the same class.

I agree that it's better to use some common user table. But if you still want to use 2 tables you can do that like this
<?php
namespace common\models;
use Yii;
use yii\base\Model;
/**
* Login form
*/
class LoginForm extends Model
{
public $username;
public $password;
public $rememberMe = true;
private $_user = false;
/**
* #inheritdoc
*/
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.
*/
public function validatePassword()
{
if (!$this->hasErrors()) {
$user = $this->getUser();
if (!$user) {
$this->addError('password', 'Incorrect username or password.');
return ;
}
if (!$user->validatePassword($this->password)) { // you need to implement this method for both models
$this->addError('password', 'Incorrect username or password.');
return ;
}
}
}
/**
* 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) {
$this->_user = Employee::findByUsername($this->username);
}
if (!$this->user) {
$this->_user = Admin::findByUsername($this->username);
}
return $this->_user;
}
}

Related

EasyAdmin 3.1 CrudControllers Symfony

I have problems setting up my Crud Controller's association fields. I want to only see users of a certain ROLE_ in the klient_id_klienta field and I don't know how to set it up.
Here is my CrudController:
class AdresKlientaCrudController extends AbstractCrudController
{
public static function getEntityFqcn(): string
{
return AdresKlienta::class;
}
/*
public function configureFields(string $pageName): iterable
{
return [
IdField::new('id'),
TextField::new('title'),
TextEditorField::new('description'),
];
}
*/
// public function configureFields(string $pageName): iterable
// {
// return [
// 'id',
// 'klient_id_klienta',
// 'miejscowosc',
// 'ulica',
// 'nr_domu',
// 'nr_lokalu',
// 'kod_pocztowy'
// ];
// }
public function configureFields(string $pageName): iterable
{
//moje
// $qb = new QueryBuilder($this->getDoctrine()->getManager());
// $qb->select('u')->from('User','u')->where('u.roles = ?ROLE_USER');
//
//
// dump(EntityFilter::new('klient_id_klienta')->apply($qb));
//koniec moje
$foreignKey = AssociationField::new('klient_id_klienta'); //here is my problem as it shows every user
return [
// IdField::new('id'),
TextField::new('miejscowosc'),
TextField::new('ulica'),
TextField::new('nr_domu'),
TextField::new('nr_lokalu'),
TextField::new('kod_pocztowy'),
//AssociationField::new('klient_id_klienta')
$foreignKey
];
}
}
And here is the user entity
<?php
namespace App\Entity;
use App\Repository\UserRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
/**
* #ORM\Entity(repositoryClass=UserRepository::class)
*/
class User implements UserInterface
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=180, unique=true)
*/
private $email;
/**
* #ORM\Column(type="json")
*/
private $roles = [];
/**
* #var string The hashed password
* #ORM\Column(type="string")
*/
private $password;
/**
* #ORM\Column(type="string", length=255)
*/
private $name;
/**
* #ORM\Column(type="string", length=255)
*/
private $surname;
/**
* #ORM\Column(type="string", length=255)
*/
private $tel;
public function getId(): ?int
{
return $this->id;
}
public function getEmail(): ?string
{
return $this->email;
}
public function setEmail(string $email): self
{
$this->email = $email;
return $this;
}
/**
* A visual identifier that represents this user.
*
* #see UserInterface
*/
public function getUsername(): string
{
return (string) $this->email;
}
/**
* #see UserInterface
*/
public function getRoles(): array
{
$roles = $this->roles;
// guarantee every user at least has ROLE_USER
return array_unique($roles);
}
public function setRoles(array $roles): self
{
$this->roles = $roles;
return $this;
}
/**
* #see UserInterface
*/
public function getPassword(): string
{
return (string) $this->password;
}
public function setPassword(string $password): self
{
$this->password = $password;
return $this;
}
/**
* #see UserInterface
*/
public function getSalt()
{
// not needed when using the "bcrypt" algorithm in security.yaml
}
/**
* #see UserInterface
*/
public function eraseCredentials()
{
// If you store any temporary, sensitive data on the user, clear it here
// $this->plainPassword = null;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
public function getSurname(): ?string
{
return $this->surname;
}
public function setSurname(string $surname): self
{
$this->surname = $surname;
return $this;
}
public function getTel(): ?string
{
return $this->tel;
}
public function setTel(string $tel): self
{
$this->tel = $tel;
return $this;
}
//moje funkcje
public function __toString()
{
// TODO: Implement __toString() method.
$userAndRole = implode($this->roles);
return $this->email.'-'.$userAndRole;
}
}
I only want to see users who have ROLE_USER
I tried to use filters but from what I see in Easyadmin documentation filters allow me to set up choices based what they get so that wouldnt work for me. I also tried to use QueryBuilder to get Users with certain ROLE_ and that also failed.
I figured it out and I want to thank you for answering. I'm posting my solution because I don't want to be one of those people who say "I figured it out" and don't post how they actually figured that out.
public function configureFields(string $pageName): iterable
{
//utworzenie wyświetlania tylko tych użytkowników, którzy maja role ROLE_USER
$association = AssociationField::new('klient_id_klienta', 'Email klienta')
->setFormTypeOption(
'query_builder', function (UserRepository $userRepository){
return $userRepository->createQueryBuilder('u')
->andWhere('u.roles LIKE :role')->setParameter('role', '%"ROLE_USER"%');
}
);
return [
// IdField::new('id'),
TextField::new('miejscowosc', 'Miejscowość'),
TextField::new('ulica', 'Ulica'),
TextField::new('nr_domu', 'Numer domu'),
TextField::new('nr_lokalu', 'Numer Lokalu'),
TextField::new('kod_pocztowy', 'Kod pocztowy'),
$association,//wywołanie klucza obcego który odfiltrowuje użytkowników
];
}
As you can see I got the users with the certain role that I wanted to get by using query builder. Amazing tool, through that query buider I can get virtually anything I want from my databases and put it in my Crud Controllers. I hope it helps someone someday.
Try this :
public function configureFields(string $pageName): iterable
{
$users = $this->entityManager->getRepository(User::class)->findBy([
'roles' => 'ROLE_USER']);
yield AssociationField::new('klient_id_klienta')->onlyOnForms()->setFormTypeOptions(["choices" => $users->toArray()]);
}

Yii2 Ldap implement kosoukhov/yii2-ldap

I am newbie with Yii2 and I need to create a login system using ldap. There is not much information about it so I hope somebody can help me.
I installed kosoukhov/yii2-ldap but don't know how to implentment it from that.
I tried editing my code as below but cannot login.
LoginForm.php
class LoginForm extends Model
{
public $username;
public $password;
public $rememberMe = true;
private $_user;
/**
* {#inheritdoc}
*/
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 validatePassword($attribute, $params)
{
if (!Yii::$app->ldap->validateUserCredentials('SAMAccountName', 'password')) {
$this->addError($attribute, 'Incorrect username LDAP or password.');
}
}
public function login()
{
if ($this->validate()) {
return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600 * 24 * 30 : 0);
}
return false;
}
protected function getUser()
{
if ($this->_user === null) {
$this->_user = User::findByUsername($this->username);
}
return $this->_user;
}
}
I would really appreciate some help here.
Thank you!

Argument 1 passed to yii\web\User::login() must implement interface yii\web\IdentityInterface

These are my files:
config/web.php
'user' => [
'identityClass' => '\app\models\User',
'enableAutoLogin' => false,
],
SiteController.php
public function actionSignin()
{
$model = new SigninForm();
if(!Yii::$app->user->isGuest)
{
return $this->goHome();
}
if($model->load(Yii::$app->request->post()) and $model->validate())
{
$identity = User::findOne(['email' => $model->email])
Yii::$app->user->login($identity);
}
return $this->render('signin',compact('model'));
}
User.php
namespace app\models;
use yii\db\ActiveRecord;
use yii\web\IdentityInterface;
class User extends ActiveRecord implements IdentityInterface
{
/* and all methods Identityinterface is here!*/
}
I'm getting an error that I'm not using IdentityInterface in my User.php model. Where is my mistake?
You need to define all the methods necessary for Implementing IdentityInterface
as given here, and 2 additional methods that would be used by the login method add them to your class first.
class User extends ActiveRecord implements IdentityInterface
{
public static function findIdentity($id)
{
return static::findOne($id);
}
public static function findIdentityByAccessToken($token, $type = null)
{
return static::findOne(['access_token' => $token]);
}
public function getId()
{
return $this->id;
}
public function getAuthKey()
{
return $this->authKey;
}
public function validateAuthKey($authKey)
{
return $this->authKey === $authKey;
}
/**
* Finds user by username
*
* #param string $username
* #return static|null
*/
public static function findByUsername($username)
{
foreach (self::$users as $user) {
if (strcasecmp($user['username'], $username) === 0) {
return new static($user);
}
}
return null;
}
/**
* Validates password
*
* #param string $password password to validate
* #return bool if password provided is valid for current user
*/
public function validatePassword($password)
{
return $this->password === $password;
}
}
Then you SigninForm should look like following
<?php
namespace app\models;
use Yii;
use yii\base\Model;
/**
* SigninForm is the model behind the login form.
*
* #property User|null $user This property is read-only.
*
*/
class SigninForm 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 bool 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::findOne($this->username);
}
return $this->_user;
}
}
Update your Signup action to the following
public function actionSignin()
{
$model = new SigninForm();
if(!Yii::$app->user->isGuest)
{
return $this->goHome();
}
if($model->load(Yii::$app->request->post()) && $model->login())
{
return $this->goBack();
}
return $this->render('signin',compact('model'));
}
And then add the following inside your config/web.php under components as it is shown in the following example:
'components'=>[
'user' => [
'identityClass' => 'app\models\User', // User must implement the IdentityInterface
'enableAutoLogin' => true,
// 'loginUrl' => ['user/login'],
// ...
]
]
You should look into documentation more thoroughly here is a good video tutorial that would guide you step by step to implement your login interface.
Hope it helps

Yii::$app->user->isGuest always true on main.php after login

I want to implement user login into yii2 basic app.everything works properly except, when I tries to access Yii::$app->user->isGuest on layout main page. it always returns true. whats going wrong here?, please help me
public function actionLogin()
{
if (!Yii::$app->user->isGuest) {
return $this->goHome();
}
$model = new LoginForm();
if ($model->load(Yii::$app->request->post()) && $model->login()) {
Yii::$app->user->isGuest; // i m getting this as false, which is correct, but after goBack(), I m getting it as true
return $this->goBack();
}
return $this->render('login', [
'model' => $model,
]);
}
Login Mehod from LoginForm.php
public function login()
{
if ($this->validate()) {
return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600*24*30 : 0);
}
return false;
}
Note : I am using custom theme, which rests outside the web folder and inside project/themes/ directory
** User Model is as follows**
<?php
namespace app\models;
use Yii;
use yii\behaviors\TimestampBehavior;
use yii\db\ActiveRecord;
use yii\web\IdentityInterface;
use yii\web\NotFoundHttpException;
class User extends ActiveRecord implements IdentityInterface {
private $id;
private $authKey;
const STATUS_DELETED = '0';
const STATUS_ACTIVE = '10';
public static function tableName() {
return '{{%user}}';
}
/**
* #inheritdoc
*/
public function behaviors() {
return [
TimestampBehavior::className(),
];
}
/**
* #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 Yii::$app->security->validatePassword($password, $this->password_hash);
}
public static function findByEmail($email) {
$user_type = ['U'];
return static::find()
->andWhere('email = :email', [':email' => $email])
->andFilterWhere(['in', 'user_type', $user_type])
->one();
}
public static function findIdentity($id) {
$user = static::find()->where(['id' => $id, 'status' => self::STATUS_ACTIVE,])->one();
if (empty($user->id)) {
\Yii::$app->session->destroy();
}
return $user;
}
public static function findIdentityByAccessToken($token, $type = null) {
$user = static::find()
->where([
'access_token' => $token,
'status' => self::STATUS_ACTIVE,
])
->one();
if (!empty($user)) {
return $user;
} else {
throw new NotFoundHttpException('Invalid access token.');
}
}
}
Remove the lines:
private $id;
private $authKey;
from User class.
You should not directly declare ActiveRecord attributes that come from database as stated in the Guide.
Note: The Active Record attributes are named after the associated table columns in a case-sensitive manner. Yii automatically defines an attribute in Active Record for every column of the associated table. You should NOT redeclare any of the attributes.

Yii2 - Unable to find 'app\models\User' in file: backend/models/User.php. Namespace missing? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
I used both namespace in this file backend/models/User.php
When I use namespace app\models; It shows Unable to find 'backend\models\User'.
If I use namespace backend\models; It shows Unable to find 'app\models\User'
<?php
//namespace app\models;
namespace backend\models;
use Yii;
use yii\base\NotSupportedException;
use yii\behaviors\TimestampBehavior;
use yii\db\ActiveRecord;
use yii\web\IdentityInterface;
class User extends ActiveRecord implements IdentityInterface
{
const STATUS_DELETED = 0;
const STATUS_ACTIVE = 10;
const ROLE_USER = 10;
/**
* #inheritdoc
*/
public static function tableName()
{
return 'admin';
}
/**
* #inheritdoc
*/
public function behaviors()
{
return [
TimestampBehavior::className(),
];
}
/**
* #inheritdoc
*/
public function rules()
{
return [
['status', 'default', 'value' => self::STATUS_ACTIVE],
['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_DELETED]],
['role', 'default', 'value' => self::ROLE_USER],
['role', 'in', 'range' => [self::ROLE_USER]],
];
}
/**
* #inheritdoc
*/
public static function findIdentity($id)
{
return static::findOne(['id' => $id, 'status' => self::STATUS_ACTIVE]);
}
/**
* #inheritdoc
*/
public static function findIdentityByAccessToken($token, $type = null)
{
throw new NotSupportedException('"findIdentityByAccessToken" is not implemented.');
}
/**
* Finds user by username
*
* #param string $username
* #return static|null
*/
public static function findByUsername($username)
{
return static::findOne(['username' => $username, 'status' => self::STATUS_ACTIVE]);
}
/**
* Finds user by password reset token
*
* #param string $token password reset token
* #return static|null
*/
public static function findByPasswordResetToken($token)
{
if (!static::isPasswordResetTokenValid($token)) {
return null;
}
return static::findOne([
'password_reset_token' => $token,
'status' => self::STATUS_ACTIVE,
]);
}
/**
* Finds out if password reset token is valid
*
* #param string $token password reset token
* #return boolean
*/
public static function isPasswordResetTokenValid($token)
{
if (empty($token)) {
return false;
}
$expire = Yii::$app->params['user.passwordResetTokenExpire'];
$parts = explode('_', $token);
$timestamp = (int) end($parts);
return $timestamp + $expire >= time();
}
/**
* #inheritdoc
*/
public function getId()
{
return $this->getPrimaryKey();
}
/**
* #inheritdoc
*/
public function getAuthKey()
{
return $this->auth_key;
}
/**
* #inheritdoc
*/
public function validateAuthKey($authKey)
{
return $this->getAuthKey() === $authKey;
}
/**
* Validates password
*
* #param string $password password to validate
* #return boolean if password provided is valid for current user
*/
public function validatePassword($password)
{
return Yii::$app->security->validatePassword($password, $this->password_hash);
}
/**
* Generates password hash from password and sets it to the model
*
* #param string $password
*/
public function setPassword($password)
{
$this->password_hash = Yii::$app->security->generatePasswordHash($password);
}
/**
* Generates "remember me" authentication key
*/
public function generateAuthKey()
{
$this->auth_key = Yii::$app->security->generateRandomString();
}
/**
* Generates new password reset token
*/
public function generatePasswordResetToken()
{
$this->password_reset_token = Yii::$app->security->generateRandomString() . '_' . time();
}
/**
* Removes password reset token
*/
public function removePasswordResetToken()
{
$this->password_reset_token = null;
}
}
I think your problem is, that you have two different models and try to use them both in one namespace, but this won't work.
You can alias one namespace, so you can use both different models.
eg.:
<?php
namespace app\models;
// there exist a model "User"
// and you wanna use also the User model under common\models\
use common\models\User as CUser;
Another solution is to prefixing the namespace to the model like
<?php
namespace app\models;
$cuser = new \common\models\User();
see PHP Namespaces explained