yii2 deny user login on backend

淺唱寂寞╮ 提交于 2019-12-07 04:29:31

问题


I have yii2 advance template with RBAC migration applied. I was trying to learn RBAC and followed the Docs 2.0.

I have logged in using database, but the front-end and back-end both get logged in with any account. I have made 2 RBAC roles (admin, user), but can't understand or find how to

restrict back-end to login non-admin user-role.

The following is the code for roles. and database entries:

namespace console\controllers;

use Yii;
use yii\console\Controller;

class RbacController extends Controller
{
    public function actionInit()
    {
        $auth = Yii::$app->authManager;

        // add "admin" role
        $admin = $auth->createRole('admin');
        $auth->add($admin);

        // add "user" role
        $user = $auth->createRole('user');
        $auth->add($user);

        $auth->assign($admin, 1);
    }
}

User Table:

admin   admin@gmail.com     20  10  1421197319  1421197319
user    user@gmail.com      10  10  1421198124  1421198124

Current rules:

'rules' => [
    [
        'actions' => ['login', 'error'],
        'allow' => true,
    ],
    [
        'actions' => ['logout', 'index'],
        'allow' => true,
        'roles' => ['@'],
    ],

回答1:


Solved - Note: The solution is not exactly RBAC but ACF.

After searching and consulting, I found the solution at This yii2 viki.

I was unclear of RBAC behavior, in that I thought it won't let a role perform specific task before some action(login, submit etc).

Actually, RBAC will let you do whatever you try, and afterwards checks for permission and block if not permitted.

Example

There is some yard sale in a house and you are free to roam around it's front yard. The house gate/entrance doesn't have any guard at front and its not locked. You try to sneak into the house and as soon you get into the house there is some security guard inside who abruptly stops you to identify yourself, he scan your information in the house security system(permissions in DB) and doesn't find your right to be in the house. He forces you out. This guard is RBAC

I needed a guard at the front gate, who won't let anybody in unless they are allowed to. And that would be ACF.

So, now I needed a way to tell the back-end system that a specific role cannot perform a specific action beforehand (i.e. deny non-admin login at back-end), this is not possible with RBAC so, for that we could use 'matchCallback' using ACF.

Backend Rules:

        'rules' => [
            [
                'actions' => ['login'],
                'allow' => true,
            ],
            [
                'actions' => ['logout', 'index'],
                'allow' => true,
                'roles' => ['@'],
                'matchCallback' => function ($rule, $action) {
                    return Yii::$app->user->identity->isAdmin;
                }
            ],
         ]

The matchCallback on True allows the actions to be performed and on False denies the action. isAdmin is a getter function that needs to be defined in User model.

namespace /common/models/User;

const ROLE_ADMIN = 20;
public function getIsAdmin()
{
    return $this->role == self::ROLE_ADMIN;
}

I have posted the complete working code of model in This yii2 viki's comments.




回答2:


You both first login user and then checking his role, there is no need for that. Your LoginForm model has getUser() method, find it after calling load() and validate(), and check role with authManager. Smth like this:

    /** @var LoginForm $model */
    $model = Yii::createObject('loginForm');

    if ($model->load(Yii::$app->request->post()) && $model->validate()) {
        /** @var User $user */
        $user = $model->getUser();
        if (!empty($user) && Yii::$app->authManager->checkAccess($user->getId(), 'admin')) {
            // Don't validate twice
            $model->login(false);
            return $this->goBack();
        } else {
            $model->addError('email', 'This user is not authorized for administration');
        }
    }
    return $this->render('login.twig', [
        'model' => $model,
    ]);

You also don't want to validate() LoginForm twice, so add $runValidation param to the login() method.

public function login($runValidation = true)
{
    if ($runValidation) {



回答3:


You should add behavior to you controller, like this:

public function behaviors()
{
    return [
        'access' => [
            'class' => AccessControl::className(),
            'rules' => [
                [
                    'actions' => ['create', 'delete', 'update'],
                    'allow' => true,
                    'roles' => ['admin'],
                ],
                [
                    'actions' => ['index', 'view'],
                    'allow' => true,
                    'roles' => ['user'],
                ],
            ],
        ],
    ];
}

or this EDIT: (rule so that anyone is allowed to access login but only admin is allowed to be logged in and access index page):

public function behaviors()
{
    return [
        'access' => [
            'class' => AccessControl::className(),
            'rules' => [
                [
                    'actions' => ['login'],
                    'allow' => true,
                    'roles' => ['?'],
                ],
                [
                    'actions' => ['index'],
                    'allow' => true,
                    'roles' => ['admin'],
                ],
            ],
        ],
    ];
}



回答4:


I have achieved this functionality by changing backend login action. here is my code, i don't know, it is a perfect solution or not, but it is working for me.

public function actionLogin()
{    
    if (!\Yii::$app->user->isGuest) {
        return $this->goHome();
    }

    $model = new LoginForm();
    if ($model->load(Yii::$app->request->post()) && $model->login()) {
        //check user roles, is user is Admin? 
        if (\Yii::$app->user->can('Admin'))
        {
            // yes he is Admin, so redirect page 
            return $this->goBack();
        }
        else // if he is not an Admin then what :P
        {   // put him out :P Automatically logout. 
            Yii::$app->user->logout();
            // set error on login page. 
            \Yii::$app->getSession()->setFlash('error', 'You are not authorized to login Admin\'s penal.<br /> Please use valid Username & Password.<br />Please contact Administrator for details.');
            //redirect again page to login form.
            return $this->redirect(['site/login']);
        }

    } else {
        return $this->render('login', [
            'model' => $model,
        ]);
    }
}


来源:https://stackoverflow.com/questions/27935155/yii2-deny-user-login-on-backend

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!