Take user back to previous page after logging in?
I have a controller called Accounts, with the views signin and signout.
The corresponding functions look like this:
function signin()
{
if (!empty($this->data))
{
//handle login
...
//save login to session
$this->Session->write('Account', $data["Account"]);
//redirect to previous page
???
}
}
function signout()
{
//delete login
$t开发者_开发百科his->Session->delete('Account');
//redirect to previous page
???
}
If the user goes to accounts/signin
it first checks to see if the form is submited if(!empty($this->data))
if yes, it logs them in, if not it renders the signin form. If they do succesfully log in, I want to redirect them to the page they were at before the signin page.
Whats the best way to do that?
Edit:
I do not think I can user a regular http referrer because technically the referrer will always be the signin in page because they go to /signin
, then submit the sign in form. So at the point where the form is submited the referrer is always /signin
. I want to redirect to where they were before that. Does that make sense?
the best way is to use cakes Auth component and let it do what it does... http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#AuthComponent::$loginRedirect
Here's how I do it with referer
I have 2 login forms, one is a form at the top of all pages for easily sign in, the other is on login action. If the user comes in using the form at the top, the form submission then goes to login page and you can use $this->referer()
to redirect the user back.
But the problem is that, if the user types the password wrong or enter invalid credential, he will then end up on the login page. If he then enters the right username+password, and redirection occurs using $this->referer()
, which in this case is itself. The user then could then either 1. get redirected back to login page again or 2. even worse can get stuck in an infinite loop b/c login will keep redirecting to itself.
So, I add some logic to check to make sure that referer is not login page. Also, I add another logic to store $this->referer()
the first time the user lands on login page, we we know where exactly the page before login page.
To store the page before login page, put this code at the end of the action (login view rendering is about to begin)
//get the current url of the login page (or current controller+action)
$currentLoginUrl = strtolower( "/" .$this->name ."/" .$this->action );
if( $this->referer() != $currentLoginUrl )
{
//store this value to use once user is succussfully logged in
$this->Session->write('beforeLogin_referer', $this->referer($this->Auth->redirect(), true)) ) ; //if referer can't be read, or if its not from local server, use $this->Auth->rediret() instead
}
Now put the code to redirect in the part of the code where authentication is succesful (or in if( $this->Auth->user() ){ }
):
//get the login page url again (by gettting its controller, or plural of Model, and this current page action and make the url)
$currentLoginUrl = strtolower( "/" .$this->name ."/" .$this->action );
//if the referer page is not from login page,
if( $this->referer() != $currentLoginUrl )
{
//use $this->referer() right away
$this->redirect($this->referer($this->Auth->redirect(), 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') );
}
Hope this works for you.
http://book.cakephp.org/view/430/referer
Use a hidden <input>
field that holds the initial referrer and gets submitted with the login data.
I don't know about the best way, but I store the attempted destination in a session variable before redirecting them to the sign in page.
Once they have signed in, I redirect them to the stored destination.
Use the AppController and UsersController to set it up
In AppController beforeFilter action
$referer = Router::url($this->url, true);
$this->Auth->loginAction = array('controller'=>'users','action'=>'login','?'=>['referer'=>$referer]);
In UsersController login action
if($this->Auth->login())
{
$this->Session->setFlash(__('Logged in successfully !'));
$redirect = $this->request->query('referer');
if(!empty($redirect))
{
return $this->redirect($this->Auth->redirectUrl($redirect));
}else{
return $this->redirect($this->Auth->redirectUrl());
}
}
CakePHP 2.x here
1. Edit AppController.php
public function beforeFilter() {
// redirect url
if($this->request->here!= '/users/login') {
$user_id = AuthComponent::user('id');
if(empty($user_id)) { $this->Session->write('redirect_url_after_login', Router::url($this->request->here, true)); }
}
This will store the url the user wanted to go before request, only if the url is not /users/login (replace with your url of login) AND if no user is logged.
2. Edit your login form. Mine was Users/login.ctp. Add an hidden field only if there is a session variable set.
$redirect_url_after_login = $this->Session->read('redirect_url_after_login');
if(!empty($redirect_url_after_login))
echo $this->Form->input('redirect_url_after_login', ['value'=>$redirect_url_after_login, 'type'=>'hidden']);
3. In your login action, add an action to overwrite the loginRedirect variable you may have set before.
public function login() {
if ($this->request->is('post')) {
if ($this->Auth->login()) {
$redirect_url_after_login = $this->request->data['User']['redirect_url_after_login'];
if(!empty($redirect_url_after_login)
&&filter_var($redirect_url_after_login, FILTER_VALIDATE_URL)
&&parse_url($redirect_url_after_login, PHP_URL_HOST)==$_SERVER['HTTP_HOST'])
return $this->redirect($redirect_url_after_login);
$this->Session->delete('redirect_url_after_login');
return $this->redirect($this->Auth->redirect());
}
I added a couple of security checks, like "is the redirect url a valid url?" and "is it redirecting towards my domain or an external domain?".
Note: I know checking $_SERVER['HTTP_HOST']
is not bulletproof, but here we're talking about preventing open redirect vulnerability, so it's enough.
精彩评论