ورود

View Full Version : نیاز به نحوه انجام مدیریت دسترسی مدیران و کاربران در بخش های مختلف -- yii2advanced



desatir7316
سه شنبه 12 اسفند 1393, 18:59 عصر
سلام دوستان
من توی نحوی دسترسی کاربران و مدیریت اون ها مشکل دارم. می خوام بخش دسترسی رو به شکل زیر پیاده کنم. ممنون می شم در مورد نحوه پیاده سازی راهنماییم کنید( سناریو رو فقط بگید، می خوام سعی کنم خودم پیاده سازی شو انجام بدم و اگه مشکلی داشتم دوباره بپرسم)



یه سری ادمین وجود دارن اگه توی backend یا frontend لاگین کنن می تونن توی هر دو بخش سایت دسترسی داشته باشن
تعداد کاربر وجود دارن که فقط به frontend می تونن دسترسی داشته باشن، یعنی اگه لاگین کردن فقط بتونن توی این بخش باشن و وقتی وارد backend شدن بهشون اجازه داده نشه یا مثل کاربری که وارد سایت نشده و نیاز با لاگین داره باهاشون برخورد بشه



بازم ممنون

MMSHFE
سه شنبه 12 اسفند 1393, 19:14 عصر
فکر میکنم با RBAC میتونید راحت پیاده سازیش کنید.

desatir7316
سه شنبه 12 اسفند 1393, 20:29 عصر
توی بخش ادمین چون چند تا ادمین هست از RBAC استفاده می کنم ولی بخش frontend همه کاربر معمولی هستن و مشکل دسترسی خاص توی این بخش نیست

مشکلی اینه که سشن های بخش frontend توی backend اجازه دسترسی نداشته باشن ولی بخش backend توی frontend بدون هیچ مشکلی دسترسی داشته باشن و شناخته بشن(چون مدیر های سایت هستن) رو نمی دونم چیکار کنم

desatir7316
سه شنبه 12 اسفند 1393, 21:25 عصر
بهتره اینطوری بگم، کاربرای بخش frontend (کاربرهای سایت) زیر مجموعه کاربرای بخش مدیریت (backend) باشند که فقط دسترسی به بخش frontend دارند ولی کاربرای بخش ادمین دسترسی به همه بخش ها دارند.

desatir7316
چهارشنبه 13 اسفند 1393, 10:48 صبح
برای درک بهتر از لاگین کردن یوزر کلاس زیر رو برای خودم مثال زدم :



class testUser implements IdentityInterface{

public $username = 'ali';

public static function findIdentity($id)
{
return 'findIdentity';
}

public static function findIdentityByAccessToken($token, $type = null)
{
return 'findIdentityByAccessToken';
}

public function getId()
{
return 'getId';
}

public function getAuthKey()
{
return 'getAuthKey';
}

public function validateAuthKey($authKey)
{
return 'validateAuthKey';
}
}

$ob = new testUser();

echo (Yii::$app->user->isGuest) ? 'is guest</br>' : 'is user<br/>';
Yii::$app->user->login($ob, 3600);
echo (Yii::$app->user->isGuest) ? 'is guest</br>' : 'is user';


این کد رو توی view گذاشتم که راحت تر تست کنم. مشکل اینجاست که کاربر لاگین نمی مونه. بعنی هرسری که refresh می کنم قبل از login می زنه is guest و بعد از لاگین می زنه is user

مشکل کجاست؟
ممنون

MMSHFE
چهارشنبه 13 اسفند 1393, 10:59 صبح
توی بخش ادمین چون چند تا ادمین هست از RBAC استفاده می کنم ولی بخش frontend همه کاربر معمولی هستن و مشکل دسترسی خاص توی این بخش نیست

مشکلی اینه که سشن های بخش frontend توی backend اجازه دسترسی نداشته باشن ولی بخش backend توی frontend بدون هیچ مشکلی دسترسی داشته باشن و شناخته بشن(چون مدیر های سایت هستن) رو نمی دونم چیکار کنم
خوب شما یک role به اسم frontend درست کنید و اون رو زیرمجموعه roleهای backend کنید. اینطوری backendها به frontend دسترسی دارن ولی برعکسش صادق نیست و کافیه شما توی frontend چک کنید و اگه مجوز backend نداشتن، خطای 403 صادر کنید. میتونید با همون SimpleAccessControl هم ترکیبش کنید. برای مثال، میتونید توی fontend اینطوری بنویسید:

public function accessRules()
{
return [
'allow' => [
'actions' => [ 'edit', 'update' ],
'expression' => 'Yii::$app->user->checkAccess(\'frontend\')',
],
'deny' => [
'actions' => [ '*' ],
],
];
}
و توی backend هم به روش مشابه دسترسی رو فقط به roleهای مشخص شده بدین.

desatir7316
چهارشنبه 13 اسفند 1393, 11:05 صبح
خوب شما یک role به اسم frontend درست کنید و اون رو زیرمجموعه roleهای backend کنید. ....

چطوری می تونم به صورت متمرکز چک کنم دسترسی رو چک کنم، منظورم اینه که به محض اینکه وارد backend شد این قضیه چک بشه؟
بیام یه کنترلر درست کنم و که از Controller ارث بری کنه و همه کنترلر های برنامه رو از این کنترلر جدید extends کنم؟

MMSHFE
چهارشنبه 13 اسفند 1393, 11:09 صبح
متدهای filters و accessRules رو به کلاس والد کنترلرها اضافه کنید. یک کلاس از Controller مشتق کنید و توی اون بنویسید و کنترلرهاتون رو از اون کلاس (بجای Controller خود Yii) مشتق کنید.

desatir7316
چهارشنبه 13 اسفند 1393, 11:14 صبح
ممنون متوجه شدم
فقط در خصوص لاگین کردن، اون چیزی که توی پست شماره پنچ (http://barnamenevis.org/showthread.php?487920-%D9%86%DB%8C%D8%A7%D8%B2-%D8%A8%D9%87-%D9%86%D8%AD%D9%88%D9%87-%D8%A7%D9%86%D8%AC%D8%A7%D9%85-%D9%85%D8%AF%DB%8C%D8%B1%DB%8C%D8%AA-%D8%AF%D8%B3%D8%AA%D8%B1%D8%B3%DB%8C-%D9%85%D8%AF%DB%8C%D8%B1%D8%A7%D9%86-%D9%88-%DA%A9%D8%A7%D8%B1%D8%A8%D8%B1%D8%A7%D9%86-%D8%AF%D8%B1-%D8%A8%D8%AE%D8%B4-%D9%87%D8%A7%DB%8C-%D9%85%D8%AE%D8%AA%D9%84%D9%81-yii2advanced&p=2182826&viewfull=1#post2182826) زدم مشکلش چیه که لاگین رو نگه نمی داره؟

تشکر

MMSHFE
چهارشنبه 13 اسفند 1393, 11:18 صبح
چک کنید سشن autoStart هست یا نه و اگه هست، ببینید شاید هربار داره عوض میشه. اگه اینطوریه بهش یک statePrefix (یا stateKeyPrefix - دقیقاً یادم نیست) مشخص بدین که هربار جدید تولید نشه. ضمناً allowAutoLogin رو هم true کنید که از کوکی استفاده کنه.

ضمناً دکمه تشکر کاربرد بهتری از پست با موضوع تشکر داره :چشمک:

desatir7316
چهارشنبه 13 اسفند 1393, 11:31 صبح
allowAutoLogin رو هم true کنید


true هست



چک کنید سشن autoStart هست یا نه و اگه هست، ببینید شاید هربار داره عوض میشه. ...


فکر نکنم از این باشه، چون وقتی از خود login پیش فرضی که توی advanced template هست استفاده می کنم این مشکل وجود نداره. یعنی پنچره tab رو هم می بندم و باز می کنم بازم کاربر رو لاگین کرده محسوب می کنه، ولی اون کد که توی پست شماره پنج هست رو تست می کنم با هر بار refresh انگاری کاربر logout و login رو دوباره انجام می ده

MMSHFE
چهارشنبه 13 اسفند 1393, 11:33 صبح
راستش با 2 زیاد کار نکردم و نمیدونم مشکل از کجاست. تحقیق میکنم اگه چیزی پیدا کردم خبر میدم.

desatir7316
چهارشنبه 13 اسفند 1393, 13:45 عصر
توی تنظیمات کلاسی user به اون اشاره می کنه رو به شکر زیر تغییر دادم :


'components' => [
'user' => [
// 'identityClass' => 'common\models\User',
'identityClass' => 'frontend\models\TestUser',
'enableAutoLogin' => true,
],

....



کلاس خودمم به این شکل هست :


<?php
namespace frontend\models;

use yii\web\IdentityInterface;
use Yii;
class TestUser implements IdentityInterface{

public $username = 'ali';

public static function findIdentity($id)
{
return 'findIdentity';
}

public static function findIdentityByAccessToken($token, $type = null)
{
return 'findIdentityByAccessToken';
}

public function getId()
{
return 'getId';
}

public function getAuthKey()
{
return 'getAuthKey';
}

public function validateAuthKey($authKey)
{
return 'validateAuthKey';
}
}




حالا پیغام خطای زیر رو داده :


yii\base\InvalidValueException The identity object must implement IdentityInterface.



خوب من که از واسط IdentityInteface توی کلاسم استفاده کردم مشکل چیه؟

خطا از این خط کذ گرفته می شه:


echo (Yii::$app->user->isGuest) ? 'is guest</br>' : 'is user</br>';

MMSHFE
چهارشنبه 13 اسفند 1393, 14:21 عصر
تمام متدهای IdentityInterface رو پیاده سازی کردین؟

desatir7316
چهارشنبه 13 اسفند 1393, 14:25 عصر
طبق این بله: http://www.yiiframework.com/doc-2.0/yii-web-identityinterface.html
البته فقط یه مقدار string رو بر می گردونن چون من نیاز به اعتبار سنجی ندارم فقط می خوام لاگین و لاگ اوت رو درست بفهمم چطوری انجام می شه

desatir7316
چهارشنبه 13 اسفند 1393, 15:18 عصر
ظاهرا خطایی که توی پست شماره ۱۳ میاد برای زمانی هست که کاربر لاگین نکرده و با رسیدن به این خط کد به وجود میاد:


echo (Yii::$app->user->isGuest) ? 'is guest</br>' : 'is user</br>';


وقتی قبل از کد بالا لاگین می کنم مشکلی نیست و کاربر رو می شناسه ولی همچنان سشن کاربر باقی نمی مونه و با رفرش از بین می ره :


Yii::$app->user->login($ob);
echo (Yii::$app->user->isGuest) ? 'is guest</br>' : 'is user</br>';

peymang
چهارشنبه 13 اسفند 1393, 15:32 عصر
تابع identity رو اینطور بنویسید ببینید جواب می ده ( یعنی از دیتابیس بگیر و بعد نیو استاتیک بر گردون)



public static function findIdentity($id)
{
$user = User::find()
->where([
"id" => $id
])
->one();
if (!count($user)) {
return null;
}
return new static($user);
}

desatir7316
چهارشنبه 13 اسفند 1393, 15:50 عصر
دیگه اون خطا رو نمی ده
findIdentity کجا صدا زده می شه و مقدار id بهش داده می شه؟
میشه یه کم توضیح بدین؟ ممنون

peymang
چهارشنبه 13 اسفند 1393, 16:34 عصر
یه جا خوندم که موقعی که میخواد \Yii::$app->user->indetity رو بگیریه findIndentity صدا زده می شه

و یه مورد دیگه که وقتی می خوایم از \Yii::$app->user->login استفاده کنیم اولین پارامترش باید یه نمونه از کلاسی باشه که واسط identity رو پیاده سازی کرده باشه
در نتیجه اولین پارامتر login میشه یه نمونه از همون کلاس


البته منم تازه کارم زیاد مطمئن نیستم :)




پ.ن : new static چیه؟ (http://stackoverflow.com/questions/5197300/new-self-vs-new-static)

desatir7316
چهارشنبه 13 اسفند 1393, 18:35 عصر
من چندان متوجه نمی شم
اگه مثالی دارید نحوه لاگین رو نشون بده ممنون می شم. فرض بشه که اصلا این کد آماده توی yii2 نیست.
یه کد باشه که خودش از ابتدا این کار رو انجام بده تا بشه فهمید

ممنون

peymang
چهارشنبه 13 اسفند 1393, 20:05 عصر
تنظیمات رو که انجام دادین، من فقط کد ها رو می زارم

migration جدول User




<?php

$tableOptions = null;
if ($this->db->driverName === 'mysql') {
// http://stackoverflow.com/questions/766809/whats-the-difference-between-utf8-general-ci-and-utf8-unicode-ci
$tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB';
}
$this->createTable('user', [
'id' => Schema::TYPE_BIGINT . ' AUTO_INCREMENT',
'email' => Schema::TYPE_STRING . '(100) NOT NULL',
'password' => Schema::TYPE_STRING . '(64) NOT NULL',
'role' => Schema::TYPE_INTEGER . '(11) NOT NULL DEFAULT 1',
'display_name' => Schema::TYPE_STRING . '(250) NOT NULL',
'phone' => Schema::TYPE_STRING . '(64) NOT NULL',
'register_at' => Schema::TYPE_DATETIME . ' NOT NULL DEFAULT \'0000-00-00 00:00:00\'',
'update_at' => Schema::TYPE_DATETIME . ' NOT NULL DEFAULT \'0000-00-00 00:00:00\'',
'activation_key' => Schema::TYPE_STRING . '(60) NOT NULL',
'status' => 'enum("active", "inactive", "block", "delete") NOT NULL DEFAULT \'inactive\'',
'auth_key' => Schema::TYPE_STRING . '(32) NOT NULL',
'access_token' => Schema::TYPE_STRING,
'password_reset_token' => Schema::TYPE_STRING,
'PRIMARY KEY (`id`)',
'UNIQUE KEY (`email`)',
], $tableOptions);


مدل User


<?php

namespace app\models\user;

use Yii;
use yii\web\IdentityInterface;

/**
* This is the model class for table "user".
*
* @property string $id
* @property string $name
* @property string $password
* @property string $email
* @property integer $role
* @property string $display_name
* @property string $phone
* @property string $register_at
* @property string $update_at
* @property string $activation_key
* @property string $status
* @property string $auth_key
* @property string $access_token
* @property string $password_reset_token
*/
class User extends \yii\db\ActiveRecord implements \yii\web\IdentityInterface
{
/**
* @inheritdoc
*/
public static function tableName()
{
return 'user';
}

/**
* @inheritdoc
*/
public function rules()
{
return [
[['password', 'email', 'display_name', 'phone', 'activation_key'], 'required'],
[['role'], 'default', 'value' => Role::USER],
[['role'], 'in', 'range' => Role::getUserRoleList()],
[['register_at', 'update_at'], 'safe'],
[['status'], 'in', 'range' => Status::getUserStatusList()],
[['status'], 'default', 'value' => Status::INACTIVE],
[['password'], 'string', 'max' => 64],
[['display_name'], 'string', 'max' => 250],
[['phone'], 'string', 'max' => 11],
// [['phone'], 'unique'],
[['activation_key'], 'string', 'max' => 60],
[['email'], 'unique'],
[['email'], 'string', 'max' => 100],
];
}

/**
* @inheritdoc
*/
public function attributeLabels()
{
return [
'id' => 'شناسه',
'password' => 'رمز عبور',
'email' => 'پست الکترونیکی',
'role' => 'نقش',
'display_name' => 'نام',
'phone' => 'تلفن همراه',
'register_at' => 'ثبت نام در',
'update_at' => 'بروزرسانی در',
'activation_key' => 'کلید فعال سازی',
'status' => 'وضعیت',
];
}

/**
* Finds an identity by the given ID.
* @param string|integer $id the ID to be looked for
* @return IdentityInterface the identity object that matches the given ID.
* Null should be returned if such an identity cannot be found
* or the identity is not in an active state (disabled, deleted, etc.)
*/
public static function findIdentity($id)
{
$user = User::find()
->where([
"id" => $id
])
->one();
if (!count($user)) {
return null;
}
return new static($user);
}

/**
* Finds user by username
*
* @param string $email
* @return static|null
*/
public static function findByEmail($email)
{
$user = User::find()
->where([
"email" => $email
])
->one();
if (!count($user)) {
return null;
}
return new static($user);
}

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

/**
* Finds an identity by the given token.
* @param mixed $token the token to be looked for
* @param mixed $type the type of the token. The value of this parameter depends on the implementation.
* For example, [[\yii\filters\auth\HttpBearerAuth]] will set this parameter to be `yii\filters\auth\HttpBearerAuth`.
* @return IdentityInterface the identity object that matches the given token.
* Null should be returned if such an identity cannot be found
* or the identity is not in an active state (disabled, deleted, etc.)
*/
public static function findIdentityByAccessToken($token, $type = null)
{
$user = User::find()
->where(["accessToken" => $token])
->one();
if (!count($user)) {
return null;
}
return new static($user);
}

/**
* Returns an ID that can uniquely identify a user identity.
* @return string|integer an ID that uniquely identifies a user identity.
*/
public function getId()
{
return $this->id;
}

/**
* Returns a key that can be used to check the validity of a given identity ID.
*
* The key should be unique for each individual user, and should be persistent
* so that it can be used to check the validity of the user identity.
*
* The space of such keys should be big enough to defeat potential identity attacks.
*
* This is required if [[User::enableAutoLogin]] is enabled.
* @return string a key that is used to check the validity of a given identity ID.
* @see validateAuthKey()
*/
public function getAuthKey()
{
return $this->auth_key;
}

/**
* Validates the given auth key.
*
* This is required if [[User::enableAutoLogin]] is enabled.
* @param string $authKey the given auth key
* @return boolean whether the given auth key is valid.
* @see getAuthKey()
*/
public function validateAuthKey($authKey)
{
return $this->auth_key === $authKey;
}
}





کنترل لاگین ( ساین)



<?php
/**
* Created by PhpStorm.
* User: peyman
* Date: 2/4/2015
* Time: 10:41 PM
*/

namespace app\controllers;


use app\models\sign\In;
use app\models\sign\Up;
use Yii;
use yii\base\Controller;
use yii\filters\AccessControl;
use yii\filters\VerbFilter;

class SignController extends Controller
{
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'only' => ['out'],
'rules' => [
[
'actions' => ['logout'],
'allow' => true,
'roles' => ['@'],
],
],
],
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'out' => ['post'],
],
],
];
}

public function actionIndex()
{
if (Yii::$app->user->isGuest) {
return Yii::$app->response->redirect(['sign/in']);
}
return Yii::$app->response->redirect(['user/']);
}

public function actionIn()
{
$model = new In();
if (Yii::$app->request->post() && $model->in()) {
$model->in();
if (Yii::$app->user->isGuest) {
$this->render('sign/in');
}
return Yii::$app->response->redirect(['user/']);
}
return $this->render('in', ['model' => $model]);
}

public function actionUp()
{
$model = new Up();
return $this->render('up', ['model' => $model]);
}

public function actionOut()
{
echo 'Ok, you now sing out';
}

public function actionActive()
{
return 'successfully active';
}
}



مدل فرم (نمای) in


<?php
/**
* Created by PhpStorm.
* User: peyman
* Date: 2/5/2015
* Time: 11:32 AM
*/

namespace app\models\sign;


use app\models\user\User;
use Yii;
use yii\base\Model;


/**
* Class In
* @package app\models\sign
*/
class In extends Model
{
/**
* @var
*/
public $email;
/**
* @var
*/
public $password;
/**
* @var bool
*/
public $rememberMe = true;

/**
* @var User
*/
private $_user;

/**
* @return array the validation rules.
*/
public function rules()
{
return [
// username and password are both required
[['email', 'password'], 'required'],
[['email'], 'email'],
[['email'], 'unique'],
[['email'], 'string', 'max' => 100],
// rememberMe must be a boolean value
['rememberMe', 'boolean'],
// password is validated by validatePassword()
['password', 'validatePassword'],
[['password'], 'string', 'max' => 64],
];
}

/**
* 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)
{
if (!$this->hasErrors()) {
if (!$this->_user || !$this->_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 in()
{
$this->getUser();
if ($this->_user) {
if ($this->_user->validatePassword($this->password)) {
return Yii::$app->user->login($this->_user, $this->rememberMe ? 3600 * 24 * 30 : 0);
}
return false;
}
return false;
}

/**
* @return null|static
*/
private function getUser()
{
$this->attributes = Yii::$app->request->post('In');
$user = new User();
$this->_user = $user->findByEmail($this->email);
return $this->_user;
}
}


نمای اکشن in


<?php

use yii\helpers\Html;
use yii\widgets\ActiveForm;

/* @var $this yii\web\View */
/* @var $model app\models\sign\in */
/* @var $form ActiveForm */
?>
<div class="in">

<?php $form = ActiveForm::begin(); ?>

<?= $form->field($model, 'email') ?>
<?= $form->field($model, 'password')->passwordInput() ?>
<?= $form->field($model, 'rememberMe')->checkbox(); ?>

<div class="form-group">
<?= Html::submitButton('Submit', ['class' => 'btn btn-primary']) ?>
</div>
<?php ActiveForm::end(); ?>

</div><!-- in -->

desatir7316
چهارشنبه 13 اسفند 1393, 23:20 عصر
findIdentity کجا صدا زده می شه و مقدار id بهش داده می شه؟
مقدار id از طریق متد ()getId بهش داده می شه، یعنی هرچی این متد بر می گردونه به عنوان پارامتر به findIdentiry ارسال می شه

peymang
پنج شنبه 14 اسفند 1393, 02:29 صبح
حالا که دوباره کدو دیدم می بینم اشتباه می کردم. چون اصلا من از findIdentity استفاده نکردم. و داخل کد بالا من از تابع findByEmail که خودم نوشتم کاربر رو گرفتم. البته این دوتا تابع هم باهم زیاد فرق ندارن در کل یه کار انجام میدن

داخل این لینک (http://www.yiiframework.com/doc-2.0/yii-web-user.html#getId()-detail) هم نوشته که getId برای بعد از لاگین هست، یعنی وقتی از \Yii::$app->user->getId() استفاده می کنیم و اگه میهمان باشه نال برمی گردونه

hamidreza_zamanian
سه شنبه 11 فروردین 1394, 13:36 عصر
شما چند راه دارید میتونید از rbac استفاده کنید که یکم سخته راه آسون تر اینه که اول یک component WebUser ایجاد کنید و توی این با استفاده از تابع checkAccess role های خودتون و سطح role هارو که از dadtaBse بیرون کشیده تعریف کنید بعد این توابع رو در accessRules کنترلر مورد نظر بکار بکیرید من خودم همیشه از این روش استفاده میکنم نمونش رو میتونید تو وب سایت

http://nazarfa.ir
مشاهده کنید و اکه تمایل داشتید کد های نمونه رو براتو قرار بدم تا استفاده کنید

png_92
چهارشنبه 13 مرداد 1395, 11:23 صبح
ممنون از کاربر peymang برای نمونه کدها.

شما تو این کدها از روش rbac دارید استفاده میکنید یا acf ؟
میشه بگید با rbac دقیقا توی چه تابعی و کدوم کنترلر چک میشه که طرف ادمینه یا کاربره؟ که بعد مطابق با اون به پنل مخصوصون هدایت بشن.