I have a REST API endpoint that i use to get a user logged in and retrieve informations about his account.
That implementation was running fine...but now it's broken.
I am using basicauth override to use USERNAME:PASSWORD instead of the token
Below controller and MODEL code
Into the response i find now all the users...instead of one
can't understand as in the first place we use findOne to select ONE user and THEN password is checked.
Maybe i missed something here :/
USER MODEL :
<?php
namespace common\models;
use yii\base\NotSupportedException;
use yii\behaviors\TimestampBehavior;
use yii\db\ActiveRecord;
use yii\web\IdentityInterface;
class User extends ActiveRecord implements IdentityInterface
{
public static function tableName()
{
return '{{%user}}';
}
public function behaviors()
{
return [
TimestampBehavior::className(),
];
}
public function rules()
{
return [
[['username', 'auth_key', 'password_hash', 'email'], 'required'],
[['status', 'created_at', 'updated_at', 'background'], 'integer'],
[['username', 'password_hash', 'password_reset_token', 'email', 'hmac_shopify', 'shop_address', 'room_id', 'wp_address', 'blog_address', 'iosRegisterID', 'androidRegisterID', 'timeZone'], 'string', 'max' => 255],
[['auth_key'], 'string', 'max' => 32],
[['account_level'], 'string', 'max' => 45],
[['username'], 'unique'],
[['email'], 'unique'],
[['password_reset_token'], 'unique'],
];
}
public static function findIdentity($id)
{
return static::findOne(['id' => $id]);
}
public static function findIdentityByAccessToken($token, $type = null)
{
return static::findOne(['auth_key' => $token]);
}
public static function findByUsername($username)
{
return static::findOne(['username' => $username]);
}
public static function findByPasswordResetToken($token)
{
if (!static::isPasswordResetTokenValid($token)) {
return null;
}
return static::findOne([
'password_reset_token' => $token,
'status' => self::STATUS_ACTIVE,
]);
}
public static function isPasswordResetTokenValid($token)
{
if (empty($token)) {
return false;
}
$timestamp = (int) substr($token, strrpos($token, '_') + 1);
$expire = Yii::$app->params['user.passwordResetTokenExpire'];
return $timestamp + $expire >= time();
}
public function getId()
{
return $this->getPrimaryKey();
}
public function getAuthKey()
{
return $this->auth_key;
return $this->hmac_shopify;
}
public function validateAuthKey($authKey)
{
return $this->getAuthKey() === $authKey;
}
public function validatePassword($password)
{
return Yii::$app->security->validatePassword($password, $this->password_hash);
}
public function setPassword($password)
{
$this->password_hash = Yii::$app->security->generatePasswordHash($password);
}
public function generateAuthKey()
{
$this->auth_key = Yii::$app->security->generateRandomString();
$this->room_id = "_r_".Yii::$app->security->generateRandomString();
}
public function generatePasswordResetToken()
{
$this->password_reset_token = Yii::$app->security->generateRandomString() . '_' . time();
}
public function removePasswordResetToken()
{
$this->password_reset_token = null;
}
public static function find()
{
return new UserQuery(get_called_class());
}
}
This is controller :
<?php
namespace api\controllers;
use yii;
use yii\rest\ActiveController;
use \common\models\User;
class RestController extends ActiveController
{
public $modelClass = '\common\models\User';
public $password_hash;
public function behaviors()
{
$behaviors = parent::behaviors();
$behaviors['verbs'] = [
'class' => \yii\filters\VerbFilter::className(),
'actions' => [
'index' => ['get', 'head'],
],
];
$behaviors['access'] = [
'class' => \yii\filters\AccessControl::className(),
'only' => ['index'],
'rules' => [
[
'actions' => ['index'],
'allow' => true,
'roles' => ['#'],
],
],
];
$behaviors['authenticator'] = [
'class' => \yii\filters\auth\HttpBasicAuth::className(),
'auth' => function ($username, $password) {
$user = \common\models\User::findByUsername($username);
if ($user ) {
$password_valid = \common\models\User::validatePassword($password,$user->password_hash);
if($password_valid)
return $user;
}
}
];
return $behaviors;
}
}
Data response from REST AUTH
<pre>
<response>
<item>...</item>
<item>...</item>
<item>...</item>
<item>...</item>
<item>...</item>
<item>...</item>
<item>...</item>
</response>
</pre>
That was def. the default behavior, i had to edit the prepareDataProvider function in in \yii2\rest\indexAction.php
Related
I encountered such a problem, a certain query "name", which the user entered, is not stored in the database, and even this stupid error with which I can not cope at all takes off .. apparently I'm more stupid than her .. please tell me what is the catch?
Here is the error in full format:
PHP Fatal Error – yii\base\ErrorException
Class 'app\models\' not found
1. in /var/www/u0598324/public_html/webstels.com/models/ShopPromoItem.php at line 40
return [
'status' => 'Статус',
];
}
public static function get($id)
{
$item = ShopPromoItem::findOne($id);
$class = 'app\\models\\' . $item->class;
return $class::findOne($id);
}
public function getTitle()
{
return Html::encode($this->title);
}
public function getPriceArray()
{
2. yii\base\ErrorHandler::handleFatalError()
$_GET = [
'username' => 'swallowsveta1997',
];
$_POST = [
'_csrf' => '2dWdOMdf_z2HrgmbtpnKKN1f-mQnpLEkeqpEkFg8zj6OoOR-sAa2DrOcQ-GG7otyuxSIXEzn6R0M5jX5Cw2cVw==',
'ShopPromoItemBuyForm' => [
'name' => 'name',
'item_id' => '1',
],
];
$_COOKIE = [
'_identity' => 'd669e918ca5f102ab0802a521e1d3fc241689f04dbb51253b7b8ab7b54713c5ca:2:{i:0;s:9:"_identity";i:1;s:50:"[22727,"gkEvlaqhpnAtz8mz4v9Fk96QOpkIrssI",2592000]";}',
'PHPSESSID' => 'abe468adef98b859d2100b97cb6da127',
'_csrf' => '542d3bc58acd73dd28aadc1e388c74c2697098a4c8d8bb4b855417ada2ebe4ffa:2:{i:0;s:5:"_csrf";i:1;s:32:"WuyFwYI342Jz0wAZfKr8kCX9vLqiS1Ri";}',
];
$_SESSION = [
'__flash' => [],
'__id' => 22727,
'__authKey' => 'gkEvlaqhpnAtz8mz4v9Fk96QOpkIrssI',
'__expire' => 1543857954,
'__captcha/site/captcha' => 'lesafiq',
'__captcha/site/captchacount' => 1,
];
Here is the model ShopPromoItem.php:
<?php
namespace app\models;
use app\helpers\BalanceHelper;
use app\models\User;
use app\models\UserBalance;
use yii\db\ActiveRecord;
use yii\helpers\Html;
use yii\helpers\Json;
class ShopPromoItem extends ActiveRecord
{
const STATUS_ENABLED = 'enabled';
const STATUS_DISABLED = 'disabled';
const STATUS_DELETED = 'deleted';
public static function tableName()
{
return '{{%shop_promo_item}}';
}
public function rules()
{
return [
];
}
public function attributeLabels()
{
return [
'status' => 'Статус',
];
}
public static function get($id)
{
$item = ShopPromoItem::findOne($id);
$class = '#app/models/' . $item->class;
return $class::findOne($id);
}
public function getTitle()
{
return Html::encode($this->title);
}
public function getPriceArray()
{
return Json::decode($this->price);
}
public function getPriceString()
{
$prices = $this->getPriceArray();
$result = '';
foreach ($prices as $currency => $price) {
$result .= '<img src="/images/' . $currency . '.png" style="vertical-align: middle; width: 24px;"> ' . BalanceHelper::convertToDigits($price);
}
return $result;
}
public function giveTo(User $user)
{
}
}
Here is ShopPromoItemBuyForm.php:
<?php
namespace app\models\forms;
use app\helpers\BalanceHelper;
use app\helpers\RefererHelper;
use app\helpers\SettingHelper;
use app\models\ShopPromoItem;
use app\models\User;
use app\models\UserPromo;
use app\models\UserBalance;
use app\models\UserOperation;
use yii\validators\IpValidator;
class ShopPromoItemBuyForm extends UserPromo
{
public $item_id;
public function rules()
{
return [
['item_id', 'required'],
['item_id', 'integer'],
['item_id', 'exist',
'targetClass' => '\app\models\ShopPromoItem',
'targetAttribute' => 'id',
'filter' => ['status' => ShopPromoItem::STATUS_ENABLED]
],
['name', 'multProtect']
];
}
public function scenarios()
{
return [
self::SCENARIO_DEFAULT => ['name']
];
}
public function multProtect()
{
return;
// disable for debug mode
if (YII_DEBUG)
return;
// check evercookie
if (isset($_COOKIE['was_promo']) && $_COOKIE['was_promo'] == "true") {
$this->addError('name', \Yii::t('app', 'Вы уже заказывали сайт с таким названием на проекте, повторный заказ сайта с таким именем запрещён'));
}
$validator = new IpValidator();
if ($validator->validate(\Yii::$app->request->userPromoIP)) {
$ip = \Yii::$app->request->userPromoIP;
$userPromo = UserPromo::find()->where(['id' => $ip])->limit(1)->one();
if ($userPromo !== null) {
$this->addError('name', \Yii::t('app', 'Вы уже заказывали сайт с таким названием на проекте, повторный заказ сайта с таким именем запрещён'));
}
} else {
$this->addError('name', \Yii::t('app', 'Вы уже заказывали сайт с таким названием на проекте, повторный заказ сайта с таким именем запрещён'));
}
}
public function buy(User $user)
{
if (!$this->validate()) {
\Yii::$app->getSession()->setFlash('warning', implode('<br />', $this->getFirstErrors()));
return false;
}
if (\Yii::$app->mutex->acquire('balance_' . $user->id)) {
\Yii::$app->db->transaction(function() use ($user) {
$item = ShopPromoItem::get($this->item_id);
$prices = $item->getPriceArray();
// check balance
foreach ($prices as $currency => $price) {
if (!$user->balance->has($currency, BalanceHelper::convertToDigits($price))) {
\Yii::$app->getSession()->setFlash('warning', \Yii::t('app', 'Недостаточно средств на балансе'));
return false;
}
}
// decrease balance
foreach ($prices as $currency => $price) {
$user->balance->decrease($currency, BalanceHelper::convertToDigits($price));
$user->operation->create(UserOperation::OPERATION_SHOP_PROMO_BUY, $currency, BalanceHelper::convertToDigits($price), [
'ShopPromoItem_id' => $this->item_id
]);
}
$item->giveTo($user);
// give reward to referer
RefererHelper::giveReward($user, UserBalance::CURRENCY_USD, BalanceHelper::convertToDigits($prices['usd']));
$message = '';
foreach ($prices as $currency => $price) {
$message .= \Yii::t('app', '{sum} долларов', ['sum' => BalanceHelper::convertToDigits($price)]);
}
\Yii::$app->getSession()->setFlash('success', \Yii::t('app', 'Вы купили «{title}»', ['title' => \Yii::t('app', $item->getTitle())]) .
'<br />' . \Yii::t('app', 'Потрачено {price}', ['price' => $message]));
return true;
});
}
}
}
UserPromo.php:
<?php
namespace app\models;
use yii\db\ActiveRecord;
use yii\helpers\Html;
class UserPromo extends ActiveRecord
{
const STATUS_ENABLED = 'enabled';
const STATUS_DISABLED = 'disabled';
const STATUS_DELETED = 'deleted';
public static function tableName()
{
return '{{%user_promo}}';
}
public function rules()
{
return [
['id', 'exist'],
['user_id', 'integer'],
['name', 'required'],
['name', 'filter', 'filter' => 'trim'],
['name', 'match', 'pattern' => '#^[\w_-]+$#i'],
['name', 'unique', 'targetClass' => self::className(), 'message' => \Yii::t('app', 'Указанное название для вашего сайта уже занято')],
['name', 'string', 'min' => 2, 'max' => 255],
];
}
public function attributeLabels()
{
return [
'status' => 'Статус',
'name' => \Yii::t('app', 'Название'),
];
}
public static function findIdentity($id)
{
$identity = static::findOne(['id' => $id]);
return $identity;
}
public static function findByName($name)
{
return static::findOne(['name' => $name]);
}
public function getName()
{
return Html::encode($this->name);
}
public function getPromo()
{
return $this->hasOne(Promo::className(), ['id' => 'promo_id']);
}
public function getUser()
{
return $this->hasOne(User::className(), ['id' => 'user_id']);
}
public function getTitle()
{
return $this->promo->getTitle();
}
public function getType()
{
return $this->promo->getType();
}
public function getProfit($type)
{
return $this->promo->{$type . '_profit'};
}
}
PromoSiteShopItem.php:
<?php
namespace app\models;
use app\helpers\BalanceHelper;
use app\helpers\SettingHelper;
class PromoSiteShopItem extends ShopPromoItem
{
public function giveTo(User $user)
{
(new UserPromo([
'user_id' => $user->id,
'promo_id' => 21,
'created_at' => time(),
'status' => UserPromo::STATUS_ENABLED
]))->save(false);
$prices = $this->getPriceArray();
// increase reserve
$value = SettingHelper::get('reserve.promo.sum') + intval(BalanceHelper::convertToDigits($prices['usd']) / 100 * 50);
SettingHelper::set('reserve.promo.sum', $value);
}
}
Promo.php:
<?php
namespace app\models;
use yii\db\ActiveRecord;
use yii\helpers\Html;
class Promo extends ActiveRecord
{
const TYPE_PROMO = 'promo';
const STATUS_ENABLED = 'enabled';
const STATUS_DISABLED = 'disabled';
const STATUS_DELETED = 'deleted';
public static function tableName()
{
return '{{%promo}}';
}
public function rules()
{
return [
['user_id', 'integer'],
];
}
public function attributeLabels()
{
return [
'status' => 'Статус',
];
}
public function getType()
{
return $this->type;
}
public function getTitle()
{
return Html::encode($this->title);
}
}
Controller:
<?php
namespace app\controllers\user\main\services;
use app\components\Controller;
use app\models\ShopPromoItem;
use app\models\forms\ShopPromoItemBuyForm;
use yii\filters\AccessControl;
use yii\web\ForbiddenHttpException;
use yii\filters\VerbFilter;
use yii\helpers\Url;
use app\models\UserPromo;
class PromoController extends Controller
{
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'rules' => [
[
'allow' => true,
'roles' => ['#'],
],
],
],
];
}
public function beforeAction($action)
{
if (\Yii::$app->params['user']['promo']['temporaryDisabled']) {
throw new ForbiddenHttpException('Заказ временно приостановлен');
}
return parent::beforeAction($action);
}
public function actionIndex()
{
$this->layout = 'page';
$items = ShopPromoItem::find()->where([
'status' => ShopPromoItem::STATUS_ENABLED
])->all();
$model = new ShopPromoItemBuyForm();
if ($model->load(\Yii::$app->request->post())) {
$model->buy(\Yii::$app->user->identity);
}
$promo = UserPromo::find()->where([
'user_id' => \Yii::$app->user->identity->id,
'status' => UserPromo::STATUS_ENABLED
])->with('promo')->orderBy('promo_id DESC')->all();
return $this->render('index', [
'items' => $items,
'model' => $model,
'promo' => $promo,
]);
}
}
When I signup and input data username, email and password. Field username is null, i don't know why. And then when I input again data username, email and password the result is error. The description error can see in the picture.
Code for models/User.php :
<?php
namespace app\models;
use Yii;
use yii\web\IdentityInterface;
use yii\db\ActiveRecord;
use yii\behaviors\TimestampBehavior;
class User extends ActiveRecord implements IdentityInterface
{
const STATUS_DELETED = 0;
const STATUS_ACTIVE = 10;
public $id;
public $username;
public $password;
public $authKey;
public $accessToken;
public static function tableName()
{
return '{{%user}}';
}
public function behaviors()
{
return
[
TimestampBehavior::className(),
];
}
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->goBack();
}
return $this->render('login', [
'model' => $model,
]);
}
public function actionLogout()
{
Yii::$app->user->logout();
return $this->goHome();
}
public function rules()
{
return
[
['status', 'default', 'value' => self::STATUS_ACTIVE],
['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_DELETED]],
];
}
/**
private static $users = [
'100' => [
'id' => '100',
'username' => 'admin',
'password' => 'admin',
'authKey' => 'test100key',
'accessToken' => '100-token',
],
'101' => [
'id' => '101',
'username' => 'demo',
'password' => 'demo',
'authKey' => 'test101key',
'accessToken' => '101-token',
],
]; */
/**
* #inheritdoc
*/
public static function findIdentity($id)
{
return static::findOne(['id' => $id, 'status' => self::STATUS_ACTIVE]);
}
/**
* #inheritdoc
*/
public static function findIdentityByAccessToken($token, $type = null)
{
}
/**
* Finds user by username
*
* #param string $username
* #return static|null
*/
public static function findByUsername($username)
{
return static::findOne(['username' => $username, 'status' => self::STATUS_ACTIVE]);
}
/**
* #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);
}
public function generatePasswordResetToken()
{
$this->password_reset_token = Yii::$app->security->generateRandomString() . '_' . time();
}
public function removePasswordResetToken()
{
$this->password_reset_token = null;
}
public function setPassword($password)
{
$this->password_hash = Yii::$app->security->generatePasswordHash($password);
}
public function generateAuthKey()
{
$this->auth_key = Yii::$app->security->generateRandomString();
}
}
Code for models/SignupForm.php :
<?php
namespace app\models;
use app\models\User;
use yii\base\Model;
use Yii;
class SignupForm extends Model
{
public $username;
public $email;
public $password;
public function rules()
{
return
[
['username', 'filter', 'filter' => 'trim'],
['username', 'required'],
['username', 'unique', 'targetClass' => '\app\models\User', 'message' => 'This username has already been
taken.'],
['username', 'string', 'min' => 2, 'max' => 255],
['email', 'filter', 'filter' => 'trim'],
['email', 'required'],
['email', 'email'],
['email', 'string', 'max' => 255],
['email', 'unique', 'targetClass' => '\app\models\User', 'message' => 'This email address has already
been taken'],
['password', 'required'],
['password', 'string', 'min' => 6],
];
}
public function signup()
{
if ($this->validate())
{
$user = new user();
$user->username = $this->username;
$user->email = $this->email;
$user->setPassword($this->password);
$user->generateAuthKey();
if ($user->save())
{
return $user;
}
}
return null;
}
}
Code controllers/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 app\components\AuthHandler;
use app\models\UserSocialMedia;
use app\models\User;
use app\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 ? 'testme' : null,
],
'auth' => [
'class' => 'yii\authclient\AuthAction',
'successCallback' => [$this, 'successCallback'],
],
];
}
public function successCallback($client)
{
// call safeAttributes method for properly format data
$attributes = $this->safeAttributes($client);
}
public function safeAttributes($client)
{
// get user data from client
$attributes = $client->getUserAttributes();
// set default value
$safe_attributes = [
'social_media' => '',
'id' => '',
'username' => '',
'name' => '',
'email' => '',
];
// get value from user attributes base on social media
if ($client instanceof \yii\autclient\client\Facebook)
{
$safe_attributes = [
'social_media' => 'facebook',
'id' => $attributes['id'],
'username' => $attributes['email'],
'name' => $attributes['name'],
'email' => $attributes['email'],
];
}
else if ($client instanceof \yii\autclient\client\Google)
{
$safe_attributes = [
'social_media' => 'google',
'id' => $attributes['id'],
'username' => $attributes['emails'] ['0'] ['value'],
'name' => $attributes['displayName'],
'email' => $attributes['emails'] ['0'] ['value'],
];
}
else if ($client instanceof \yii\autclient\client\Twitter)
{
$safe_attributes = [
'social_media' => 'twitter',
'id' => $attributes['id'],
'username' => $attributes['screen_name'],
'name' => $attributes['name'],
'email' => '-',
];
}
else if ($client instanceof \yii\autclient\client\Github)
{
$safe_attributes = [
'social_media' => 'github',
'id' => $attributes['id'],
'username' => $attributes['login'],
'name' => $attributes['name'],
'email' => $attributes['email'],
];
}
return $safe_attributes;
}
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->goBack();
}
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();
}
return $this->render('contact', [
'model' => $model,
]);
}
public function actionAbout()
{
return $this->render('about');
}
public function actionCommentary()
{
$model = new \app\models\Commentary();
// return $this->render('commentary',['model' => $model,]);
// Jika form di sumbit dengan method POST
if (Yii::$app->request->post())
{
$model->load(Yii::$app->request->post());
if($model->validate()){
Yii::$app->session->setFlash('success','Thank You');
}
else {
Yii::$app->session->setFlash('error','Sorry, something wrong');
}
return $this->render('result_commentary',['model'=>$model,]);
}
else{
return $this->render('commentary',['model'=>$model,]);
}
}
public function actionQuery()
{
$db = Yii::$app->db;
$command = $db->createCommand('SELECT * FROM employee');
$employees = $command->queryAll();
// Ekstrak data
foreach ($employees as $employee)
{
echo "<br>";
echo $employee['id']." ";
echo $employee['name']." ";
echo $employee['age']." ";
}
}
public function actionQuery2()
{
$db= Yii::$app->db;
// return a single row
$employee = $db->createCommand('SELECT * FROM employee where id=1')
->queryOne();
echo $employee['id']." ";
echo $employee['name']." ";
echo "(".$employee['age'].")";
echo "<hr>";
// return a single column (the first column)
$names = $db->createCommand('SELECT name FROM employee')->
queryColumn();
print_r($names);
echo "<hr>";
// Binding Parameter
$employee = $db->createCommand('SELECT * FROM employee WHERE id=:id'
,['id'=>2])->queryOne();
// INSERT (table name, column values)
//$db->createCommand()->insert('employee',['name'=>'Nur','age'=>'99',
// ])->execute();
// UPDATE (table name, column values, condition)
//$db->createCommand()->update('employee',['age'=>'30'], 'id = 7')
//->execute();
// DELETE (table name, condition)
//$db->createCommand()->delete('employee', 'id = 7')
//->execute();
// table name, column name, column values
$db->createCommand()->batchInsert('employee',
['name', 'age'],
[
['Nur', 25],
['Dani', 32],
['Nurul', 40],
])->execute();
}
public function actionActiveRecord()
{
$employees = \app\models\Employee::find()->all();
foreach($employees as $employee)
{
echo "<br>";
echo $employee->id." ";
echo $employee->name." ";
echo "(".$employee->age.") ";
}
}
public function actionSignup()
{
$model = new \app\models\SignupForm();
// use session
$session = Yii::$app->session;
$attributes = $session['attributes'];
if ($model->load(Yii::$app->request->post()))
{
if ($user = $model->signup())
{
if ($session->has('attributes'))
{
// add data user_social_media
$user_social_media = new UserSocialMedia([
'social_media' => $attributes['social_media'],
'id' => (string)$attributes['id'],
'username' => $attributes['username'],
'user_id' => $user->id,
]);
$user_social_media->save();
}
if (Yii::$app->getUser()->login($user))
{
return $this->goHome();
}
}
}
if ($session->has('attributes'))
{
// set form field with data from social media
$model->username = $attributes['username'];
$model->email = $attributes['email'];
}
return $this->render('signup', ['model' => $model,
]);
}
}
Remove User model attributes' declarations that are present in your database table:
public $id;
public $username;
These will be handled by ActiveRecord and by adding it manually you are preventing this process.
I am new in Yii2 and I try to make AccessControl and success
but the problem is after I success for login and redirect to other page
my Identity _attributes always are null.So if I check with Yii::$app->user->isGuest the return value is always true
this is my LoginHandler.php
<?php
namespace app\models;
use Yii;
use yii\base\Model;
/**
* Login form
*/
class LoginHandler extends Model
{
public $user_name;
public $user_password;
public $rememberMe = true;
private $_user;
/**
* #inheritdoc
*/
public function rules()
{
return [
[['user_name', 'user_password'], 'required'],
[['user_name', 'user_password'], 'string', 'max' => 100],
['user_password','authenticate'],
];
}
public function authenticate($attribute, $params){
// return true;
}
public function login()
{
if ($this->validate()) {
return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600 * 24 * 30 : 0);
} else {
return false;
}
}
protected function getUser()
{
if ($this->_user === null) {
$this->_user = User::findByUsername($this->user_name);
}
return $this->_user;
}
}
LoginController
<?php
namespace backend\controllers;
use Yii;
use app\models\user;
use app\models\LoginHandler;
class LoginController extends \yii\web\Controller
{
public function actionIndex()
{
return $this->render('index');
}
public function actionSignin(){
$user = User::findByUsername('admin');
$model = new LoginHandler();
if(Yii::$app->request->post()){
$data = Yii::$app->request->post();
$model->attributes = $data;
if ($model->login()) {
return $this->redirect(['/user/test']);
}else{
die('test');
}
}
return $this->render('login');
}
}
My User.php as model
namespace app\models;
use Yii;
/**
* This is the model class for table "user".
*
* #property integer $user_id
* #property string $user_name
* #property string $user_password
*/
class User extends \yii\db\ActiveRecord implements \yii\web\IdentityInterface{
public $id;
public $authKey;
/**
* #inheritdoc
*/
public static function tableName()
{
return 'user';
}
/**
* #inheritdoc
*/
public function rules()
{
return [
[['user_name', 'user_password'], 'required'],
[['user_name', 'user_password'], 'string', 'max' => 100]
];
}
/**
* #inheritdoc
*/
public function attributeLabels()
{
return [
'user_id' => 'User ID',
'user_name' => 'User Name',
'user_password' => 'User Password',
];
}
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;
}
public static function findByUsername($username){
return static::findOne(['user_name' => $username]);
}
}
and the last is my configuration main.php
<?php
$params = array_merge(
require(__DIR__ . '/../../common/config/params.php'),
require(__DIR__ . '/../../common/config/params-local.php'),
require(__DIR__ . '/params.php'),
require(__DIR__ . '/params-local.php')
);
return [
'id' => 'app-backend',
'basePath' => dirname(__DIR__),
'controllerNamespace' => 'backend\controllers',
'bootstrap' => ['log'],
'modules' => [],
'components' => [
'user' => [
'identityClass' => 'backend\models\User',
'loginUrl' => ['login/signin'],
'enableAutoLogin' => true,
],
'log' => [
'traceLevel' => YII_DEBUG ? 3 : 0,
'targets' => [
[
'class' => 'yii\log\FileTarget',
'levels' => ['error', 'warning'],
],
],
],
'errorHandler' => [
'errorAction' => 'site/error',
],
],
'params' => $params,
];
Thanks in advance.
You mentioned AccessControl in your question. In Yii2 AccessControl is the special behavior class to manage access rules inside controller:
http://www.yiiframework.com/doc-2.0/yii-filters-accesscontrol.html
and I don't see AccessControl in you code.
Anyway.
Most probably the problem is in your implementation of User class.
Looking at your code I can imagine that the table structure is: user_id (PK), user_name, user_password.
If so, then the method getId() returns variable
($this->id) which is never initialized. But this method is used by Yii to store current user in session. In your case it should return $this->user_id.
And if you wish to make remember me working, you should implement correctly getAuthKey and validateAuthKey too.
Here is details:
http://www.yiiframework.com/doc-2.0/guide-security-authentication.html
If this not helps, then show your table structure and code of view which pass authentication data to LoginController
It looks you should check for
Yii::$app->user->identity
I have a table in my DB called 'member' where I intend to store username, password and all other related info of a user and I want to use those username/password for login instead yii2's default User.php model. I have been trying for almost a day and modified the Member.php model but can't make it work. Every time I use my custom username/password from db, it says username or password is incorrect.
Can anyone please help me out? Thanks in advance. :)
FYI, I have no such field in member table such as authKey or accessToken. I have tried all the related stackoverflow posts but in vein.
Member.php Model
namespace app\models;
use Yii;
use yii\web\IdentityInterface;
class Member extends \yii\db\ActiveRecord implements IdentityInterface
{
public static function tableName()
{
return 'member';
}
public function rules()
{
return [
[['username', 'password', 'first_name', 'last_name', 'role'], 'required'],
[['created_by_date', 'last_modified_by_date'], 'safe'],
[['username', 'password', 'role', 'created_by_id', 'last_modified_by_id'], 'string', 'max' => 50],
[['first_name', 'last_name', 'middle_name', 'phone', 'mobile'], 'string', 'max' => 100],
[['email'], 'string', 'max' => 250],
[['address_line1', 'address_line2', 'address_line3'], 'string', 'max' => 512]
];
}
public function attributeLabels()
{
return [
'id' => 'ID',
'username' => 'Username',
'password' => 'Password',
'first_name' => 'First Name',
'last_name' => 'Last Name',
'middle_name' => 'Middle Name',
'email' => 'Email',
'phone' => 'Phone',
'mobile' => 'Mobile',
'address_line1' => 'Address Line1',
'address_line2' => 'Address Line2',
'address_line3' => 'Address Line3',
'role' => 'Role',
'created_by_id' => 'Created By ID',
'created_by_date' => 'Created By Date',
'last_modified_by_id' => 'Last Modified By ID',
'last_modified_by_date' => 'Last Modified By Date',
];
}
public static function find()
{
return new MemberQuery(get_called_class());
}
public static function findIdentity($id)
{
$dbUser = self::find()
->where([
"id" => $id
])
->one();
if (!count($dbUser)) {
return null;
}
return new static($dbUser);
}
public static function findIdentityByAccessToken($token, $userType = null)
{
$dbUser = self::find()
->where(["accessToken" => $token])
->one();
if (!count($dbUser)) {
return null;
}
return new static($dbUser);
}
public static function findByUsername($username)
{
$dbUser = self::find()
->where(["username" => $username])
->one();
if (!count($dbUser)) {
return null;
}
return $dbUser;
}
public function getId()
{
return $this->id;
}
public function getAuthKey()
{
return $this->authKey;
}
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;
}
}
config/web.php
'user' => [
'identityClass' => 'app\models\Member',
'enableAutoLogin' => true,
],
I didnt change the User.php model. Here it is:
namespace app\models;
class User extends \yii\base\Object implements \yii\web\IdentityInterface
{
private static $users = [
'100' => [
'id' => '100',
'username' => 'admin',
'password' => 'admin',
'authKey' => 'test100key',
'accessToken' => '100-token',
],
'101' => [
'id' => '101',
'username' => 'demo',
'password' => 'demo',
'authKey' => 'test101key',
'accessToken' => '101-token',
],
];
/**
* #inheritdoc
*/
public static function findIdentity($id)
{
return isset(self::$users[$id]) ? new static(self::$users[$id]) : null;
}
/**
* #inheritdoc
*/
public static function findIdentityByAccessToken($token, $type = null)
{
foreach (self::$users as $user) {
if ($user['accessToken'] === $token) {
return new static($user);
}
}
return null;
}
/**
* 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;
}
/**
* #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;
}
}
You should make sure you change the getUser() method on models/LoginForm.php to use your Member model class, otherwise it will keep validating against the default User model.
public function getUser() {
if ($this->_user === false) {
$this->_user = Member::findByUsername($this->username);
}
return $this->_user;
}
Also, here is an example of my own User model class
namespace app\models;
use Yii;
class User extends \yii\db\ActiveRecord implements \yii\web\IdentityInterface {
const SCENARIO_LOGIN = 'login';
const SCENARIO_CREATE = 'create';
public static function tableName() {
return 'user';
}
public function scenarios() {
$scenarios = parent::scenarios();
$scenarios[self::SCENARIO_LOGIN] = ['username', 'password'];
$scenarios[self::SCENARIO_CREATE] = ['username', 'password', 'authKey'];
return $scenarios;
}
public function rules() {
return [
[['username', 'email'], 'string', 'max' => 45],
[['email'], 'email'],
[['password'], 'string', 'max' => 60],
[['authKey'], 'string', 'max' => 32],
[['username', 'password', 'email'], 'required', 'on' => self::SCENARIO_CREATE],
[['authKey'], 'default', 'on' => self::SCENARIO_CREATE, 'value' => Yii::$app->getSecurity()->generateRandomString()],
[['password'], 'filter', 'on' => self::SCENARIO_CREATE, 'filter' => function($value) {
return Yii::$app->getSecurity()->generatePasswordHash($value);
}],
[['username', 'password'], 'required', 'on' => self::SCENARIO_LOGIN],
[['username'], 'unique'],
[['email'], 'unique'],
[['authKey'], 'unique'],
];
}
public function attributeLabels() {
return [
'id' => 'Id',
'username' => 'Username',
'password' => 'Password',
'email' => 'Email',
'authKey' => 'authKey',
];
}
public static function findIdentity($id) {
return self::findOne($id);
}
public static function findIdentityByAccessToken($token, $type = null) {
throw new NotSupportedException('"findIdentityByAccessToken" is not implemented.');
}
public static function findByUsername($username) {
return static::findOne(['username' => $username]);
}
public function getId() {
return $this->getPrimaryKey();
}
public function getAuthKey() {
return $this->authKey;
}
public function validateAuthKey($authKey) {
return $this->authKey === $authKey;
}
public function validatePassword($password) {
return Yii::$app->getSecurity()->validatePassword($password, $this->password);
}
}
Make sure the methods from IdentityInterface you implement but don't want to use throw an exception, just like i do on the findIdentityByAccessToken method.
You should extend User class with your Member class and set in main config:
[...]
'modules' => [
'user' => [
'class' => 'member class
'modelMap' => [
'User' => 'app\models\member',
More info: yii 2 : override user model
On adding a new record, insert only ID, other fields empty is added.
public function actionSignup()
{
$model = new User();
if(Yii::$app->request->post()) {
$model->id = 122;
$model->username = 'user123';
$model->password = 'pass123';
...
$model->save(false);
}
return $this->render('signup',['model' => $model]);
}
var_dump shows that all necessary data are brought in $model...
User model:
<?php
namespace app\models;
use yii\captcha\Captcha;
use yii\db\ActiveRecord;
class User extends ActiveRecord implements \yii\web\IdentityInterface
{
public $id;
public $username;
public $password;
public $user_fio;
public $user_email;
public $user_group;
public $verifyCode;
private static $users;
public function actions()
{
return [
'captcha' => [
'class' => 'yii\captcha\CaptchaAction',
'fixedVerifyCode' => YII_ENV_TEST ? 'index' : null,
],
];
}
public function rules()
{
return [
[['username', 'user_fio', 'user_email', 'password', 'user_group'], 'required'],
[['username', 'user_fio', 'password'], 'string', 'max' => 70],
[['user_email'], 'string', 'max' => 150],
["verifyCode", "captcha", 'captchaAction' => 'site/captcha'],
];
}
public static function tableName()
{
return '{{users}}';
}
public function attributesLabels()
{
return [
'username' => 'username',
'password' => 'password',
'user_fio' => 'fiouser',
'user_mail' => 'email',
'user_group' => 'group',
'verifyCode' => 'code with image'
];
}
public static function findIdentity($id)
{
$user = Users::find()->where(['id' => $id])->one();
if(!count($user)) return null;
else
return new static($user);
}
public static function findIdentityByAccessToken($token, $type = null)
{
$user = Users::find()->where(['auth_key' => $token])->one();
if(!count($user)) return null;
else
return new static($user);
}
public static function findByUsername($username)
{
$user = Users::find()->where(['username' => $username])->one();
if(!count($user)) return null;
else
return new static ($user);
}
public function getId()
{
return $this->id;
}
public function getAuthKey()
{
return $this->authKey;
}
public function validateAuthKey($authKey)
{
return $this->authKey === $authKey;
}
public function validatePassword($password)
{
return $this->password === $password;
}
}
screenshots table Users:
[Table with emptys fields] http://i.stack.imgur.com/EowUl.jpg
[Table structure] http://i.stack.imgur.com/lpdZM.jpg
I changed nothing, only I added action of registration of the new user
You have declared database fields as public class fields ($id, $username, etc.), so this fields are assigned instead of internal ActiveRecord fields. Try to delete or comment out class public fields.