สำหรับ Yii Framework 2 นั้น โดยทั่วไปเราสามารถใช้ AccessControl ในการจัดการสิทธิ์การเข้าถึงได้เพียงแค่ตรวจสอบว่า login หรือ guest (ยังไม่ login) แต่ถ้าหากเราต้องการกำหนดสิทธิ์เพิ่มเติมให้กับ user เช่น สิทธิ์ admin, staff, member เป็นต้นนั้น เราจะต้องสร้าง Rule class ขึ้นมาเพื่อตรวจสอบ แล้วกำหนดใน Access Control ให้เรียกใช้งาน โดยมีขั้นตอนในการเขียนดังนี้

เพิ่ม field role ในตาราง user

ให้ทำการเพิ่ม field role ในตาราง user จากนั้นกำหนด role ใน class common\models\User.php ตัวอย่าง User.php

<?php
namespace common\models;

use Imagine\Image\Box;
use Yii;
use yii\base\NotSupportedException;
use yii\behaviors\TimestampBehavior;
use yii\db\ActiveRecord;
use yii\helpers\FileHelper;
use yii\imagine\Image;
use yii\web\IdentityInterface;
use yii\web\UploadedFile;

/**
 * User model
 *
 * @property integer $id
 * @property string $username
 * @property string $password_hash
 * @property string $password_reset_token
 * @property string $email
 * @property string $auth_key
 * @property integer $status
 * @property integer $created_at
 * @property integer $updated_at
 * @property string $password write-only password
 * @property integer $role
 */
class User extends ActiveRecord implements IdentityInterface
{


    const STATUS_DELETED = 0;
    const STATUS_NOT_ACTIVE = 5;
    const STATUS_ACTIVE = 10;

    const ROLE_ADMIN = 9;
    const ROLE_USER = 1;
    const ROLE_MODERATOR = 5;

    public $password;
    public $password_confirm;
    public $profile_firstname;
    public $profile_lastname;
    public $is_change_password;


    /**
     * @inheritdoc
     */
    public static function tableName()
    {
        return '{{%user}}';
    }

    /**
     * @inheritdoc
     */
    public function behaviors()
    {
        return [
            TimestampBehavior::className(),
        ];
    }

    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [['email', 'username', 'password_hash'], 'required'],
            ['status', 'default', 'value' => self::STATUS_ACTIVE],
            ['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_NOT_ACTIVE, self::STATUS_DELETED]],
            [['username', 'email', 'auth_key'], 'unique'],
            [['password_hash', 'password_reset_token', 'email', 'username'], 'string', 'max' => 255],
            [['auth_key'], 'string', 'max' => 32],
            ['username', 'unique', 'targetAttribute' => ['username' => 'username']],
            ['email', 'unique', 'targetAttribute' => ['email' => 'email']],
            [['username', 'password_hash', 'email'], 'required', 'on' => 'update_account'],
            ['role', 'default', 'value' => self::ROLE_USER],
            ['role', 'in', 'range' => [self::ROLE_USER, self::ROLE_MODERATOR, self::ROLE_ADMIN]]
        ];
    }

    /**
     * @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 bool
     */
    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();
    }

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

    public function getProfile()
    {
        return $this->hasOne(Profile::className(), ['user_id' => 'id']);
    }


    public function attributeLabels()
    {
        return [
            'profile_firstname' => 'Firstname',
            'profile_lastname' => 'Lastname'
        ];
    }

    public function attributeHints()
    {
        return [
            'is_change_password' => 'If you selected this checkbox, please insert new password in Password Hash.'
        ];
    }
}

สร้าง Rule เพื่อตรวจสอบ role

ทำการสร้าง Rule เพื่อทำการตรวจสอบ role โดยเขียนใน common\components\HanumanRule.php (ชื่อไฟล์และ class อาจเป็นชื่ออื่นได้)

<?php
/**
 * Created by HanumanIT Co., Ltd.
 * User: Manop Kongoon
 * Date: 21/1/2560
 * Time: 16:41
 */

namespace common\components;


use yii\filters\AccessRule;

class HanumanRule extends AccessRule
{
    protected function matchRole($user)
    {
        if(empty($this->roles)){
            return true;
        }
        foreach($this->roles as $role){
            if($role === '?'){
                if($user->getIsGuest()){
                    return true;
                }
            }else if($role === '@'){
                if(!$user->getIsGuest()){
                    return true;
                }
            }else if(!$user->getIsGuest() && $role === $user->identity->role){
                return true;
            }
        }
        return false;
    }
}

ปรับ code ใน controller เพื่อตรวจสอบ rule

ทำการแก้ไข Access Control ใน controller เพื่อตรวจสอบ rule ตามสิทธิ์ role ใน user โดยปกติจะมีการกำหนด access control ลักษณะดังนี้

public function behaviors()
{
    return [
        'access' => [
            'class' => \yii\filters\AccessControl::className(),
            'only' => ['create', 'update', 'index', 'delete'],
            'rules' => [
                
                // allow authenticated users
                [
                    'allow' => true,
                    'roles' => ['@'],
                ],
                // everything else is denied
            ],
        ],
    ];
}

แก้ไขให้ตรวจสอบ rule จาก HanumanRule ที่สร้างขึ้น โดย index, create ให้เข้าถึงได้ทุกคน update เฉพาะ moderator กับ admin ส่วน delete ให้เฉพาะ admin 

class PostController extends Controller
{
   
   public function behaviors()
       {
           return [
               'verbs' => [
                   'class' => VerbFilter::className(),
                   'actions' => [
                       'delete' => ['post'],
                   ],
               ],
               'access' => [
                   'class' => AccessControl::className(),
                   // We will override the default rule config with the new AccessRule class
                   'ruleConfig' => [
                       'class' => HanumanRule::className(),
                   ],
                   'only' => ['index','create', 'update', 'delete'],
                   'rules' => [
                       [
                           'actions' => ['index','create'],
                           'allow' => true,
                           // Allow users, moderators and admins to create
                           'roles' => [
                               User::ROLE_USER,
                               User::ROLE_MODERATOR,
                               User::ROLE_ADMIN
                           ],
                       ],
                       [
                           'actions' => ['update'],
                           'allow' => true,
                           // Allow moderators and admins to update
                           'roles' => [
                               User::ROLE_MODERATOR,
                               User::ROLE_ADMIN
                           ],
                       ],
                       [
                           'actions' => ['delete'],
                           'allow' => true,
                           // Allow admins to delete
                           'roles' => [
                               User::ROLE_ADMIN
                           ],
                       ],
                   ],
               ],            
           ];
       }

 

มานพ กองอุ่น

มานพ กองอุ่น : Developer

ความคิดเห็น

หากบทเรียนรู้มีความผิดพลาดประการใด หรือมีข้อเสนอแนะกรุณาแจ้ง contact@programmerthailand.com