i just read about creating operation for defining the authorization rules...there was a code in the book which is as follows
# protected/controllers/SiteController.php::actionSetup()
$auth = Yii::app()->authManager;
$auth->createOperation('createPage',"create a new page");
$auth->createOperation('updatePage',"update a page");
The first argument is the identifier that specifies the operation uniquely...second is the description of the operation....
NOW my QUESTION is
where is the ACTION attached to the operation..it just consists of the name and the description...?? Even if i assign this operation to a user....how will the rule identify that which action has been assigned to it???
You use the auth manager assign function to give users access to an auth item.
See http://www.yiiframework.com/doc/api/1.1/IAuthManager#assign-detail
E.g.
Yii::app()->authManager->assign('createPage', $idOfMyUser);
You can then use the access rules in a controller to control who can perform an action
Like:
public function accessRules()
{
array('allow',
'actions' => array('create'),
'roles' => array('createPage')),
array('deny'),
);
}
Note that Roles, Operations and Tasks are essentially the same thing, they are just a ways of seperating or groping auth items
Related
While I type localhost/yiitest in the address bar I want to view the login page. I searched the web, but wasn't able to find out how to do this.
Can anybody help me?
If youre using yii1, add a filter to your controller:
public function filters()
{
return array('accessControl'); // perform access control for CRUD operations
}
public function accessRules()
{
return array(
array(
'allow', // allow authenticated users to access all actions
'users'=>array('#'),
),
array('deny'),
);
}
If not logged user try to access any page, he will be redirected to site/login (you can change it in config). Of course if u add this accessRules in SiteController you have to add additional rule to allow not logged in users to access actionLogin().
I want to force all users to log in before accessing pages of my site. I have followed Larry Ullman's tutorial Forcing Login for All Pages in Yii.
According to the tutorial you can make an exception for some pages to avoid redirecting to the log in page. In order to check the current controller it has checked $_GET value. My problem is that I have used urlManager to rewrite the URL and $_GET gives me a null value. Is there any method I can use to get the current controller and action in the score of my class?
I tried the following but it is not accessible in the scope of my component class:
Yii::app()->controller->getId
Did you try:
Yii::app()->controller->id
and:
Yii::app()->controller->action->id
?
Yes you can get the current controller/action route, by reversing urlManager rule:
Yii::app()->urlManager->parseUrl(Yii::app()->request)
As now in Yii2
get current controller name
Yii::$app->controller->id
current controller object
Yii::$app->controller
current action name:
Yii::$app->controller->action->id
current route:
Yii::$app->requestedRoute
Using Yii2, obtain the current controller object with:
Yii::$app->controller
From the controller, obtain the current action as a string using:
Yii::$app->controller->action->id
In Yii2:
The problem of calling Yii::$app->controller->id is that when you call it somewhere (example: in one of your top-level abstract controller), Yii::$app->controller might not be instantiated yet, so it will return error.
Just directly call urlManager to map request to route:
var_dump(Yii::$app->urlManager->parseRequest(Yii::$app->request))
Try Yii::app()->controller->getRoute()
If I get you question correctly, you are basically trying to stop access to certain actions in the controller from being accessed without being logged in right?
If this is what you are after, the correct method to do it is this :
Make a actionMethod() in the controller like so :
class SomeController extends CController{
public function actionSomeAction(){
... More code...
}
After that, you can access the site using : path/to/application/controllerName/actionName
Now if you want to force the user to log in before accessing the action, do this :
Make an access control like so :
/**
* #return array action filters
*/
public function filters()
{
return array(
'accessControl', // perform access control for CRUD operations
);
}
/**
* Specifies the access control rules.
* This method is used by the 'accessControl' filter.
* #return array access control rules
*/
public function accessRules()
{
return array(
array('allow', // allow authenticated user to perform 'create' and 'update' actions
'actions' => array('**yourActionMethodName**'),
'users' => array('#'),
),
array('deny', // deny all users
'users' => array('*'),
),
);
}
Now only authenticated users would be able to access the URL.
I hope it solved your problem.
If you simply want to check if the user is a guest and if he is, send him to the login page everytime:
In the config/main.php, add the following :
'defaultController' => 'controllerName/actionMethod',
And in that controller just add the above access rule. Now, by default you are opening the site to an access controlled method. So it would automatically redirect you to the login page.
Even another method :
Just add this in the views/layouts/main.php
<?php
if(Yii::app()->user->isGuest)
{
$this->redirect('/site/login');
}
?>
if (Yii::$app->requestedAction->id == "index") {
//do something
}
I have a controller in a CakePHP application in which I have a bunch of actions. I'm using the ACL Component to manage which user is allowed to execute which actions in my controller. I have an isAuthorized() action in my controller to check if a certain logged user is allowed to execute a requested action that looks like this:
function isAuthorized()
{
switch($this->action)
{
case 'myAction':
$user_id = $this->Auth->user('id'); // the id of the connected user
if($user_id)
{
return $this->Acl->check(
array('model' => 'MyModel', 'foreign_key' => $user_id),
'controllers/MyController/myAction'
);
}
break;
}
}
As you can see above, all I'm doing is check if the connected user is allowed to execute myAction by using the method check of the Acl component. The problem I have with this approach is that this check is done every single time myAction is called. Is there a way to tell Cake to perform this check only one time (on the first call of the action for example)?. By checking every single time if a user is allowed to execute a controller action that slows down the application a lot.
Any help or suggestions is appreciated
Thank you
Technically speaking, HTTP is stateless and each request does not have any affinity to any other request from the same user. State-fullness is created by using sessions.
You could store the ACL check result in a session variable. But you would need some way to reset it if the users access were to change while logged in.
I don't know the best approach for access rules of the creator of model in the controller. I usually using like this :
public function accessRules() {
return array(
...
array('allow', // allow authenticated user to perform 'create' and 'update' actions
'actions' => array('docrop', 'cropimages','upload','setting','updateprivacy','updateuser','changepassword'),
'expression' => array($this,'isCreator'),
),
...
);
}
And then in that controller I'm using this function to check the correct access rules
public function isCreator(){
$hasil=false;
if(isset($_GET['id'])){
$idUser=$_GET['id'];
$hasil=$idUser==Yii::app()->user->id?true:false;
}
return $hasil;
}
And then If I want to create the url I always use the id parameter in that url. Is this the best approach? Or there is an alternative ways that better than this?
Your current approach would allow users to change the id in the url, giving them access to all actions. If you really would like to keep this method, I suggest using some kind of hashing method to make it less brute-forceable in combination with e.g. his ip address for more security: $hashFromUrl == md5(Yii::app()->user->id . CHttpRequest::getUserHostAddress()). Nonetheless I discourage this approach.
As the method is called isCreator(), I assume that you want to check whether the current user is the creator/author of an existing model in the database. Can't you use a creatorId field for this model to compare against the current user's id? No client side hacks are required then.
I am doing an app that requires authentication. In the index page of the app, I specified access rules like this
public function accessRules() {
return array(
array('deny',
'actions'=>array('index','register','login','password'),
'users'=>array('#'),
),
array('allow',
'users'=>array('*')
),
);
}
At the first rule, the actions 'index','register','login' and 'password' are made unaccessible to authenticated users. However, I do not want to show this message
Unauthorized
You are not authorized to perform this action.
You do not have the proper credential to access this page.
If you think this is a server error, please contact the webmaster.
...to the authenticated users when they try to access those actions. Instead, I want to redirect them to another page. It would be useful if i could do something like this at the first rule
array('redirect',
'actions'=>array('index','register','login','password'),
'users'=>array('#'),
'url'=>array('home/index'),
),
Since Yii v1.1.11 you can do the same thing with a callback and a closure, and just the default classes:
array('deny',
'actions'=>array('index','register','login','password'),
'users'=>array('#'),
'deniedCallback' => function() { Yii::app()->controller->redirect(array ('/home/index')); }
),
They 'll make you an offer you can't refuse
Starting with Yii v1.1.11 CAccessRule defines the deniedCallback property that easily allows you to define a redirect when access is denied. I don't want to steal Iain Gray's thunder, so go upvote his answer (thanks to the commenter who alerted me to this as well).
The original answer follows.
Option 1: extend Yii to enable this functionality (correct)
To do this we will need to write our own classes to be used instead of CAccessRule and CAccessControlFilter. For CAccessRule we just need to add one additional property:
class MyAccessRule extends CAccessRule {
public $redirect; // just add this property
}
For CAccessControlFilter we want to make it recognize the value of this property and act upon it. To do this, we need to override the preFilter method. Starting from the stock implementation, make a few changes:
class MyAccessControlFilter extends CAccessControlFilter {
protected function preFilter($filterChain)
{
$app=Yii::app();
$request=$app->getRequest();
$user=$app->getUser();
$verb=$request->getRequestType();
$ip=$request->getUserHostAddress();
foreach($this->getRules() as $rule)
{
if(($allow=$rule->isUserAllowed($user,
$filterChain->controller,
$filterChain->action,
$ip,
$verb))>0) // allowed
break;
else if($allow<0) // denied
{
// CODE CHANGED HERE
$request->redirect($app->createUrl($rule->redirect));
return false;
}
}
return true;
}
}
Then we also need to override the setRules method, to instruct the filter to use the MyAccessRule class instead of the standard CAccessRule. Again, we modify the stock implementation by changing the line
$r=new CAccessRule;
to read
$r=new MyAccessRule;
After creating these classes, we have to also inject them into Yii's pipeline. To do this, override filterAccessControl on the base controller class; again, taking the stock implementation as reference and making a small change:
public function filterAccessControl($filterChain)
{
$filter=new MyAccessControlFilter; // CHANGED THIS
$filter->setRules($this->accessRules());
$filter->filter($filterChain);
}
That's it! You can now take advantage of the extra functionality in any controller by supplying the new redirect parameter to the access control filters like this:
public function accessRules() {
return array(
array('deny',
'actions'=>array('index','register','login','password'),
'users'=>array('#'),
'redirect'=>array('home/index'),
),
);
}
Option 2: implement access control inside each action (to be avoided)
If you are not comfortable with subclassing Yii's core components, another option that I do not recommend is to embed both access control and redirection logic inside each controller action that you want to protect, or overriding the beforeAction method on your controllers to cover multiple actions from one location.
this one worked for me since yii 1.1.11:
array('deny', // deny all users
'users'=>array('*'),
'deniedCallback' => $this->redirect('/')
),
or use a static method in a Class:
'deniedCallback' => array('ClassName', 'staticMethodName'),
$request->redirect($app->createUrl($rule->redirect));
Should be:
if(is_array($rule->redirect) && isset ($rule->redirect[0])){
$request->redirect($app->createUrl($rule->redirect[0]));
}