I would like to authorize users based on few roles. All visitors should be able to reach method show. So I wrote in AppController:
public function beforeFilter(Event $event) {
$this->Auth->allow(['show']);
}
It works.
In initialize() method of AppController I've got also:
$this->loadComponent('Auth', [
'authorize' => 'Controller'
]);
I would like to allow logged users with role "user" to reach all "index", and "add" methods, so I wrote in AppController:
public function isAuthorized($user) {
if (isset($user['role']) && $user['role'] === 'admin') {
return true;
}
if (isset($user['role']) && $user['role'] === 'user') {
$this->Auth->allow(['index', 'logout', 'add']);
}
return false;
}
Admin can reach all methods as expected. User logged with role "user" can't reach "index" or "add" method. How can I fix this?
Instead of using your logic to add additional Auth allows, just use the logic to determine if they're in an action they're allowed, by checking the action, and return true if they're authorized.
public function isAuthorized($user) {
// Admin allowed anywhere
if (isset($user['role']) && $user['role'] === 'admin') {
return true;
}
// 'user' allowed in specific actions
if (isset($user['role']) && $user['role'] === 'user') {
$allowedActions = ['index', 'logout', 'add'];
if(in_array($this->request->action, $allowedActions)) {
return true;
}
}
return false;
}
(obviously this code could be shortened to your liking, but it shows the concept)
I find this solution to be great and easier to maintain.
//in all controllers that you want to restrict access
public function isAuthorized($user)
{
//an array since we might want to add additional roles
$possibleRoles = array('admin');
return $this->confirmAuth($user['role'], $possibleRoles);
}
//in AppController
public function confirmAuth($userRole, $allowedRoles)
{
return in_array($userRole, $allowedRoles);
}
Related
I've been stuck here for a while. I hope I can clearly explain the issue. I'm trying to have separate pages for admin and user. For that, I have created an admin middleware. Now when I login, it redirects me to the same page either its admin or user. I want it to go to admin dashboard when admin logs in and to the user home when user logs in. I hope the issue is clear.
Here is the AdminMiddleware code:
public function handle($request, Closure $next)
{
if(Auth::user()->user_type == 'admin') //If usertype is admin
{
return $next($request);
}
else {
return redirect('home');
}
}
Here are the routes code:
Route::get('/','HomeController#index');
//For Admin
Route::group(['middleware' => ['auth','admin']], function() {
Route::get('/admin','HomeController#home_page');
Route::get('/users-list', 'UserController#users_list');
});
Here is the HomeController code:
public function index()
{
return view('home', compact('currantWorkspace'));
}
I've added the Middleware path to kernel.php file.
I'll be happy to provide any other details if needed. Any solutions/suggestions will be highly appreciated.
Edit
I've tried this, but still issue.
protected function redirectTo(){
if (Auth::user()->user_type != 'admin') {
return 'admin';
//return redirect('/admin');
}
else {
return 'home';
//return redirect('/');
}
}
I think the redirectTo function is not working, or not checking the if/else conditions
Why don't you create an 'if, else' statement in your login function like:
if(Auth::user()->user_type == "Admin"){
return Redirect::route('dashboard');
}else if(Auth::user()->user_type == "Standard User"){
return Redirect::route('home');
}
Change the route as follows.
Route::get('/','HomeController#index')->name('home');
Route::group(['middleware' => ['auth','admin']], function()
{
Route::get('/admin','HomeController#home_page')->name('admin.home');
Route::get('/users-list', 'UserController#users_list');
});
Change the redirect statement in middleware as
public function handle($request, Closure $next)
{
if(Auth::user()->user_type == 'admin') //If usertype is admin
{
return $next($request);
}
else
{
return redirect()->route('home');
OR
return redirect('/');
}
}
There are a few problems, currently, the key thing is that the middleware you defined is not being called when anyone tries to log in.
To make it work I think you just need to add this to your LoginController.php
protected function authenticated()
{
if (Auth::user()->user_type == 'admin') {
return redirect('dashboard');
}
return redirect('home');
}
This method basically tells laravel what you want to do after the user is logged in.
I am trying to implement email account verification.
If a user has not confirmed their email, they can still log in, but they should not be able to access any actions in the account module. So for example, if they try to access:
/account/profile/edit
/account/listing/add
it should redirect the user to /account/default/confirm, which displays a message saying:
"You have not yet confirmed your account, please click the link in the confirmation email, or click here to resend the confirmation email".
I have tried the following:
BaseController:
class BaseController extends Controller
{
protected function findUser($id)
{
if (($model = User::findOne(['id' => $id, 'deleted_at' => null])) !== null) {
if ($model->confirmed_at == null) {
return $this->redirect(['/account/default/confirm']);
}
return $model;
} else {
throw new NotFoundHttpException('The requested page does not exist.');
}
}
}
ProfileController:
class ProfileController extends BaseController
{
public function actionEdit()
{
$user = $this->findUser(Yii::$app->user->id);
$profile = $user->profile; // getProfile() relation in User model
return $this->render('index', [
'profile' => $profile,
]);
}
}
The problem I am having is that it gives me an error:
"Trying to get property 'profile' of non-object".
I think the reason for the error is because it seems to be assigning the redirect to $user, instead of actually terminating the request at the redirect.
I know instead of doing return $this->redirect() in findUser() I can do it in the controller action, but then I would have to do this for every action. Is there a better way of doing this? Maybe some kind of access rules or behaviour?
Here try to check !empty() before $model access like
class BaseController extends Controller
{
protected function findUser($id)
{
if (($model = User::findOne(['id' => $id, 'deleted_at' => null])) !== null) {
if (!empty($model->confirmed_at)) {
return $model;
}
return $this->redirect(['/account/default/confirm']);
} else {
throw new NotFoundHttpException('The requested page does not exist.');
}
}
}
$this->redirect() will return response object - it looks like really bad design if such method may return completely unrelated object (Response or User). You probably should call Application::end() to terminate application, so redirection will take effect without continuing execution of controller action.
protected function findUser($id) {
if (($model = User::findOne(['id' => $id, 'deleted_at' => null])) !== null) {
if ($model->confirmed_at == null) {
$this->redirect(['/account/default/confirm']);
Yii::$app->end();
}
return $model;
}
throw new NotFoundHttpException('The requested page does not exist.');
}
I have a employee table which it contains emp_id,email,password and roles. I have given user and admin as a value for the field roles. I have also created webuser component which it extends CWebUser. This is my webuser code.
class WebUser extends CWebUser
{
public function checkAccess($operation, $params=array())
{
if (empty($this->id)) {
// Not identified => no rights
return false;
}
$role = $this->getState("roles");
if ($role === 'admin') {
return true; // admin role has access to everything
}
return ($operation === $role);
}
}
This is my UserIdentity code.
class UserIdentity extends CUserIdentity
{
private $_id;
public function authenticate()
{
$user= Employee::model()->find('LOWER(email)=?',array(strtolower($this->username)));
if($user===null)
$this->errorCode=self::ERROR_USERNAME_INVALID;
else if(!$user->validatePassword($this->password))
$this->errorCode=self::ERROR_PASSWORD_INVALID;
else
{
$this->_id=$user->emp_id;
$this->setState('roles',$user->roles);
$this->username=$user->email;
$this->errorCode=self::ERROR_NONE;
}
return $this->errorCode==self::ERROR_NONE;
}
}
This is my controller code.
public function accessRules()
{
return array(
array('allow', // allow all users to perform 'index' and 'view' actions
'actions'=>array('index','view'),
'users'=>array('*'),
),
array('allow', // allow authenticated user to perform 'create' and 'update' actions
'actions'=>array('create'),
'users'=>array('#'),
),
array('allow', // allow admin user to perform 'admin' and 'delete' actions
'actions'=>array('admin','update','delete'),
'roles'=>array('admin'),
),
array('deny', // deny all users
'users'=>array('*'),
),
);
}
It seems everything is fine. But when i try to update then it is not working and i have tried this for a person who have a admin value for the roles. Please correct me if am wrong.
I think problem is in checkAccess - you need to access a model Employee
class WebUser extends CWebUser
{
private $_model = null;
public function getModel(){
if (!$this->isGuest && $this->_model === null) {
$this->_model = Employee::model()->findByPk($this->id);
}
return $this->_model;
}
public function checkAccess($operation, $params=array()){
return $this->model->roles == 'admin';
}
}
If your app will not be compicated this should work.
But better use PhpAuthManager (or DbVersion) with full RBAC support
I just a newbie in Yii. I have read http://www.yiiframework.com/wiki/328/simple-rbac/ and followed all instructions there, but I had error User.roles is not defined when I tried to login. Here is my UserIdentity.php
<?php
class UserIdentity extends CUserIdentity
{
private $_id;
public function authenticate()
{
$user = User::model()->findByAttributes(array
('username'=>$this->username));
if($user===null){
$this->errorCode=self::ERROR_USERNAME_INVALID;
}
else{
if($user->password!==$user->encrypt($this->password)){
$this->errorCode=self::ERROR_PASSWORD_INVALID;
}
else{
$this->_id = $user->username;
$this->setState('roles', $user->roles);
$this->errorCode=self::ERROR_NONE;
}
}
return !$this->errorCode;
}
public function getId(){
return $this->_id;
}
}
And then EWebUser.php
<?php
class EWebUser extends CWebUser
{
public function checkAccess($operation, $params=array())
{
if (empty($this->id)) {
// Not identified => no rights
return false;
}
$role = $this->getState("roles");
if ($role === 'admin') {
return true; // admin role has access to everything
}
// allow access if the operation request is the current user's role
return ($operation === $role);
}
}
At last accessRules method in UserController.php
public function accessRules()
{
.....
return array(
array('allow', // allow admin user to perform 'admin' and 'delete' actions
'actions'=>array('admin','delete'),
//'users'=>array('admin'),
'roles'=>array('admin'),
.....
);
}
I hope anyone can help me solve this problwm, thank you very much
In my web application I need to show the type of user in the view in protected/views/layouts/main.php.
But I am getting this error:
"CException" ."Property "CWebUser.type" is not defined."
I am unable to get rid of this error , how to resolve this issue?
I am using this line of code to display the type of user
array('label'=>'Logout ('.Yii::app()->user->type.')', 'url'=>array('/site/logout'),
'visible'=>!Yii::app()->user->isGuest)
I tried by using user->user_type also but not working
My code for the UserIdentity class
class UserIdentity extends CUserIdentity
{
private $_id;
public function authenticate()
{
$user = User::model()->findByAttributes(array(
'email'=>$this->username));
if ($user === null) {
$this->errorCode=self::ERROR_USERNAME_INVALID;
} else if ($user->pass !==
hash_hmac('sha256', $this->password,
Yii::app()->params['encryptionKey']) ) {
$this->errorCode=self::ERROR_PASSWORD_INVALID;
} else {
$this->errorCode=self::ERROR_NONE;
$this->setState('type', $user->user_type);
$this->setState('id', $user->id);
$this->_id = $user->id;
}
return !$this->errorCode;
}
public function getId() {
return $this->_id;
}
}
Also since I am using Role based access control I have changed the code in user.php for assigning roles to users
My code to assign users type.
public function afterSave() {
if (!Yii::app()->authManager->isAssigned(
$this->type,$this->id)) {
Yii::app()->authManager->assign($this->type,
$this->id);
}
return parent::afterSave();
}
And I have used this code in my SiteController for assigning roles to users
$auth->assign($user->type,$user->id);
If I;m right in what's happening, there may be times when you're not logged in that Yii is trying to access the user settings. As you're not logged in you can't access them, hence the error. So in the label, check that user isset()
'label' => (isset(Yii::app()->user->type) ? Yii::app()->user->type : '')