CakePHP how to redirect to a page after login - cakephp

So I made the application so every time I try to visit a page on it it redirects me to login, thats good, but after I log in I want it to redirect me to a certain page, but it doesnt, it just sends me back to page it redirected me from. I used the code from CakePHP cookbook for login:
public function login()
{
$this->request->allowMethod(['get', 'post']);
$result = $this->Authentication->getResult();
if ($result->isValid()) {
$redirect = $this->request->getQuery('redirect', [
'controller' => 'Buslines',
'action' => 'index',
]);
return $this->redirect($redirect);
}
if ($this->request->is('post') && !$result->isValid()) {
$this->Flash->error(__('Invalid username or password'));
}
}
Now all I need to know is how do I redirect to buslines/index after login.

You are explicitly requesting the redirect query variable and use it for redirection, so what you're seeing is the expected behavior, as that query variable contains the previously visited endpoint where access was denied. The second argument, the default value, will never be used unless the redirect query variable somehow gets lost.
Note that this redirect is only for when authentication was successful, so if you always want to redirect to a fixed endpoint after successful authentication, then just pass the corresponding value directly to redirect(), eg:
return $this->redirect([
'controller' => 'Buslines',
'action' => 'index',
]);
You also don't have to configure the authentication service's queryParam option then.

Related

Cakephp redirect in isAuthorized method not working

So after login in isAuthorized method I'm trying to redirect user based on a condition. But problem is it's not redirecting. Below the code that I have tried.
protected function isAuthorized($LoginUser)
{
if ($this->getTable('Users')->hasCompany($LoginUser) == false){
$this->redirect(['controller'=>'Companies','action'=>'edit']);
dd("hello");
}
}
It's not redirecting and getting hello message. How can I redirect after login user to another page based on condition ?
As mentioned in the comments, the auth component's authorization objects are supposed to return a boolean, and depending on that, let the component do the unauthorized handling-
What you could do, is for example dynamically set the component's unauthorizedRedirect option (and probably also authError) from the controller's authorization handler for that specific case (I guess you'd also have to exclude the respective company controller's action from that check, as otherwise you'll end up in an infinite redirect loop):
if (!$this->getTable('Users')->hasCompany($LoginUser)) {
$message = __('You must provide company information in order to proceed.');
$url = \Cake\Routing\Router::url([
'controller' => 'Companies',
'action' => 'add'
]);
$this->Auth->setConfig([
'authError' => $message,
'unauthorizedRedirect' => $url,
]);
return false;
}
// ...
return true;
If you find yourself in a situation where there's no such possibility, brute forcing a redirect by throwing a \Cake\Http\Exception\RedirectException could be a solution too, even though it's ideally avoided, it's better than dying, as it will at least emit a clean redirect response:
$url = \Cake\Routing\Router::url([
'controller' => 'Companies',
'action' => 'add'
]);
throw new \Cake\Http\Exception\RedirectException($url);
See also
Cookbook > Controllers > Components > AuthComponent > Configuration options

CakePHP Auto redirect Admin 404 to login

I am using the Auth component and ACL to give permission to roles and redirect them to /login if they don't have the proper rights.
That works fine for all existing controller/action. But when ever I enter a none existing controller action http://www.mypage.de/fake/bla I get a notFoundExeption.
My issue with that is, that the user sees my admin layout, because the 404 is rendered within the admin layout template.
Is there a way to say that admin (or any prefix) is always restricted and users that are not logged in get redirected to the login page?
What I came up with is this, but I don't like it, because I would have to do the same for all other prefixes.
/**
* AppController::afterFilter()
*
* #return void
*/
function afterFilter() {
if ($this->response->statusCode() === 404 && !empty($this->request->params['admin'])) {
$url = Router::url(
array(
'admin' => false,
'plugin' => false,
'controller' => 'users',
'action' => 'login'
)
);
$this->Common->flashMessage(__('You are not authorized to access that location.'), 'error');
return $this->redirect($url);
}
}
Your code actually does the trick pretty well, but there is no way to automatically do this for every prefix, except maybe doing it in a foreach loop:
function afterFilter() {
if($this->response->statusCode() === 404) {
foreach(array('admin', 'otherprefix') as $prefix) {
if(!empty($this->request->params[$prefix])) {
[...]
}
}
}
}
If you want to treat all 404 errors the same – regardless of the possible prefixes – you could just change the layout for your 404 error:
function afterFilter() {
if($this->response->statusCode() === 404) {
$this->layout = 'default';
}
}
This way, no one would see the admin layout on any 404 page.

cakephp referrer after auth deny

How do I get the page that was denied access by the Auth component using CakePHP 2.x? If I use the referer() function, it gives me the page that linked to the denied action. Here's my code:
public function login() {
//get the current url of the login page (or current controller+action)
$currentLoginUrl = "/login";
if ($this->request->is('post')) {
$this->User->recursive = -1;
$user = $this->User->find(
'first',
array(
'conditions' => array(
'User.username' => $this->request->data['User']['username'],
'User.password' => AuthComponent::password($this->request->data['User']['password'])
)
)
);
if ($user && $this->Auth->login($user['User'])) {
//if the referer page is not from login page,
if( $this->referer() != $currentLoginUrl )
//use $this->referer() right away
$this->redirect($this->referer('/admin', true)); //if referer can't be read, or if its not from local server, use $this->Auth->rediret() instead
else
//if the user lands on login page first, rely on our session
$this->redirect( $this->Session->read('beforeLogin_referer') );
}
else
$this->Session->setFlash('Username or password is incorrect', 'default', array('class' => 'alert-danger'));
}
if( $this->referer() != $currentLoginUrl )
//store this value to use once user is succussfully logged in
$this->Session->write('beforeLogin_referer', $this->referer('/admin', true) ) ; //if referer can't be read, or if its not from local server, use $this->Auth->rediret() instead
}
So basically what happens is I'm not logged in, and I'm at this url:
'http://localhost/hotelguide/hotels/view/17/'
and I click on a link that would take me to
'http://localhost/hotelguide/hotels/review/17/'
but that requires a user to be logged in, so it redirects me to the login page, which, when I debug referrer(), it gives me this:
'http://localhost/hotelguide/hotels/view/17/'
What am I doing wrong?
When you use Auth component in CakePHP and try to access a restricted site, it redirects you to login page and saves the referring page in session. Session key Auth.redirect holds the value you're looking for - the page that you were trying to access.
Look at the __unauthenticated() method of AuthComponent. It includes the code responsible for writing session value to Auth.redirect. If you don't want to use AuthComponent, you can check how it is implemented in the component and write your own solution based on the method I have mentioned.
$this->referer() will not provide you the correct referrer url for you. If you want to get referrer url just use $this->Session->read('Auth.redirect');
You can find exact url you are looking for by $this->Session->read('Auth.redirect');
$this->referer() value update every time when you reload the page.

Login link with current page passed as query string that then uses it to send user back

How would I create a login link on a CakePHP page that contains a query string with the current page so for example: domain.com/login/?back=/posts/This_is_a_post
and then how would I use this in the login method to send the user BACK to this url?
I have tried this: <?php echo $this->Html->link('Log in', array('controller'=>'users','action'=>'login','admin'=>false, '?'=> array('back'=>$this->here)), array('escape'=>false)); ?>
but it does this on the url /login?back=%2Fportfolio%2Fgt%2FCreatHive
how do I get it to NOT change the / in the URL
Cheers
The best way to do this is to store the last page visited in a session at some point, probably when the page is loaded in the login action or something. Why you ask? As an attacked could make a link to your site eg: yoursite.com/login?back=mysite.com/login, so that when the user logs in, you send them to my site which is an exact duplicate of your login form and get them to login again. Voila, an attacker could now easily phish your users info.
With sessions there'd be no url encoding problems either. Just something like this in your login action:
$this->Session->set('back_to', $this->referer());
// Then if they have logged in:
$backTo = $this->Session->read('back_to');
if($backTo) {
$this->redirect($back_to);
} else {
$this->redirect($this->Auth->redirect());
}
Update - Try using named parameters instead:
For your link:
echo $this->Html->link('My Link', array('controller' => 'users', 'action' => 'login', 'url' => $url));
In your users login:
function login(){
if($this->Session->read('Auth.User')){
$url = $this->params['named']['url']
// encode/decode url
$this->redirect("$url");
}
}
You can always use urlencode() and urldecode() for the $url variable.
You also need to make sure your form also sends the URL back to the login function:
echo $this->Form->create('User', array('controller' => 'users', 'action' => 'login', 'url' => $url));

admin auth check not working

for my client's website I have an admin section- only thing is my admin routing doesn't seem to be password protected. I added the admin protection with a tutorial on how to set up a user system, and have placed the following code in app_controller.php:
function beforeFilter() {
// if an admin route is requested and not logged in
$user = $this->Session->read('User');
if(isset($this->params['admin']) && $this->params['admin'] && is_null($user)) {
// set Flash and redirect to login page
$this->Session->setFlash('You need to be logged in for that action.','default',array('class'=>'flash_bad'));
$this->redirect(array('controller'=>'users','action'=>'login','admin'=>FALSE));
}
}
& in my app/config/routes.php I have this:
Router::connect('/login', array('controller' => 'users', 'action' => 'login'));
Router::connect('/admin/logout', array('controller' => 'users', 'action' => 'logout'));
which I'm pretty sure is missing something for the protection.
I can still access other admin areas without logging in though, i.e. theowlhouse.com.au/admin/bookings.
What am I doing wrong? The admin page for the users model is the only protected one.
Thanks :)
It looks like you're confusing prefix routing with using the auth component. Note that prefix routing was called 'admin routing' prior to version 1.3.
You don't need to use admin routing to use the auth component. Let's start with just getting the auth component set up. In your app controller, make sure you have it included in your components array:
var $components = array('Auth');
Once you've done that, users will be directed to a login page unless they are logged in. To allow anonymous users to access an action, you make a called to $this->Auth->allow('action name'); So, for example, say you want to allow unauthenticated users to use the index() and view() actions in your items controller, but not add() or edit(). In your items_controller.php, you would set up the beforeFilter() to make a call:
function beforeFilter() {
parent::beforeFilter();
$this->Auth->allow(array(
'index',
'view'
));
}

Resources