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
}
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 am using Yii framework for my application. My application contain 4 controllers in which I want to pass value from one controller to another.
Let us consider site and admin controller. In site controller, I manage the login validation and retrieves admin id from database. But I want to send admin id to admin controller.
I try session variable, its scope only within that controller.
Please suggest the possible solution for me.
Thanks in advance
You want to use a redirect:
In the siteController file
public function actionLogin()
{
//Perform your operation
//The next line will redirect the user to
//the AdminController in the action called loggedAction
$this->redirect(array('admin/logged', array(
'id' => $admin->id,
'param2' => $value2
)));
}
in the adminController file
public function loggedAction($id, $param2)
{
//you are in the other action and params are set
}
I have some website http://www.example.com, I have a controller abc in which I have method index() which loads my website's view. I have made my controller abc as default controller so that when user enters example.com , he can directly see the view. I cannot change this default controller in any case. Now I want that if user enters example.com/1234 , where 1234 is profile number, so it should show that profile . if it is example.com/5678 , then it should show 5678's profile. The problem I am facing is , if user enters example.com/1234 then it will throw a 404 error because I don't have any controller 1234, even if I make a check in my default controller's index function if($this->uri->segment(3) == True) it is throwing 404 error. Any help would be appreciated.
In your routes file add this change:
$route['(:any)'] = 'abc/index/$1';
Then in abc controller:
public function index($profile=NULL)
{
$profile = $this->uri->segment(1, 0);
echo($profile);// just for checking, of course, you will remove this later, + the rest of your code, related to user id
Typically there is a one-to-one relationship between a URL string and its corresponding controller class/method.
In the routes.php (config folder) you can change the defoult controller and routing also. Read the Wildcards (secion) in documentation below
More informacion read the documentation
Create a pre_controller hook in config/hooks.php. Remember to enable hooks in config/config.php if you haven't already.
Example:
$hook['pre_controller'][] = array(
'class' => 'Thehook',
'function' => 'check_for_profile',
'filename' => 'thehook.php',
'filepath' => 'hooks'
);
Then create your hook method check_for_profile() in hooks/thehook.php. This method can check for a matching profile and display or redirect accordingly. If no profile match is found you can call the show_404() method.
This way, your existing controller/method paths are unaffected, and all of your routes remain intact.
If you're redirecting within the hook, use this format:
header("Location: controller/method");
..rather than
redirect('controller/method');
...as the latter will result in a continuous loop
Add in routes.php
$route["(.*)"] = 'abc/userid/$1';
Then in main controller abc add
public function userid()
{
$userid=$this->uri->segment(1);
echo ($userid);
}
Now you have userid in this function :)
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]));
}