Wrong return url in Yii framework - php

I have used Yii::app()->user->returnUrl but it always redirect me to localhost/index.php. Is there any particular configuration or some pieces of code that other programs that I must write? If you have another solutions let me know it.

#aslingga, can you please explain what you're trying to do with returnUrl? Are you just trying to get back to where you were after logging in, or are you using it somewhere else?
This is from the Yii documentation:
Redirects the user browser to the
login page. Before the redirection,
the current URL (if it's not an AJAX
url) will be kept in returnUrl so that
the user browser may be redirected
back to the current page after
successful login. Make sure you set
loginUrl so that the user browser can
be redirected to the specified login
URL after calling this method. After
calling this method, the current
request processing will be terminated.
In other words, if the page you're trying to request requires authentication, the URI of the page you're on gets stored in a session variable. Then, once you've logged in, it takes you back to that page.
One way I'd recommend troubleshooting is to do a print_r($_SESSION); just to make sure the returnUrl is actually being stored. Then you'll be able to check if index.php is being stored as returnUrl or if you're just being redirected there for some reason.
Looking at the CWebUser methods getState and setState might also be helpful.

I know this question is old but maybe this will help someone out since I didn't couldn't find a decent answer anywhere.
How getReturnUrl works
Setting a default return URL for your Yii app requires a bit of customization. The way it works out of the box is that you specify the default return URL each time you call it:
Yii::app()->user->getReturnUrl('site/internal');
The idea being that if a user were to visit a page that requires authentication, they will get redirected to the login page, but not before the site running
Yii::app()->user->setReturnUrl('site/visitedpage');
Now when the user logs in, they will be returned to the page they intended to go to.
While I like that functionality, having to set the default return URL each time is dumb. If you want to change the default return URL, you have to go find it throughout your code. I suppose you could set the value in a site parameter and call
Yii::app()->user->getReturnUrl(Yii::app()->params['defaultReturnUrl']);
I don't think I have to explain why that solution is annoying too.
My Solution
So when getReturnUrl is called without any parameters, it returns either '/index.php' or just '/'. This is fine in some cases, but not always. This is better IMO.
First, extend the CWebUser class and add the following extras
class WebUser extends CWebUser {
// default return URL property
public defaultReturnUrl;
// override the getReturnUrl method
public function getReturnUrl($defaultUrl=NULL) {
if ($defaultUrl === NULL) {
$defaultReturnUrl = $this->defaultReturnUrl;
}
else {
$defaultReturnUrl = CHtml::normalizeUrl($defaultUrl);
}
return $this->getState('__returnUrl',$defaultReturnUrl);
}
}
Now, let's add a couple items to the user component array.
'user' => array(
'class' => 'WebUser',
'defaultReturnUrl' => 'site/internal'
)
Not only does this allow you to set a default return URL in the config, but also maintains the ability to set a different default return URL and use the setReturnUrl functionality.

I think, you must set it:
Yii::app()->user->setReturnUrl('controller/action');

Related

Losing session data after POST from third party website

I have a Laravel site that redirects to a payment provider (external third party website). When the user completes their payment, they are redirected back to my site via a POST request.
The issue I'm having is that the user's session is lost when they return to the confirmation page.
I wondered if this was behaviour of PHP generally but it seems to be specific to Laravel.
I have checked my sessions.php config file and can confirm the following is set 'expire_on_close' => false,.
I've created a very basic example of the issue below
My website (pre-sale)
Controller
public function redirect()
{
$user = Auth::user();
dd($user); // returns User model;
redirect()->away('http://www.example.com');
}
Payment provider website
Note, the request is sent via the application within the browser - not a callback. There is also no button. I just want to demonstrate the POST back to the Laravel site.
<html>
<head></head>
<body>
<form method="POST" action="http://www.example.com/payment/confirmation">
<input type="submit">
</form>
</body>
</html>
My website (post-sale)
Route
Route::post('/payment/confirmation', 'Payment\PaymentController#confirmation');
Controller
public function confirmation()
{
$user = Auth::user();
dd($user); // Returns null
}
I have added the path to the VerifyCsrfToken middleware's exception array. Is there anything within Laravel that would destroy the session on POSTing via an external website? I'm sure I'm missing something obvious. Thanks
I was able to resolve this issue by changing 'same_site' => 'lax', to 'same_site' => null, in config/session.php. This appears to be a new setting in Laravel 7+.
I'm not sure if there are any security implications caused by this change without further reading but this, for now, fixes the problem. It would be a nice feature to somehow whitelist certain domains.
Setting the 'same_site' => null might not work as expected again because Standards related to the Cookie SameSite attribute recently changed https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite
The new default is now Lax, so if you set your same_site to null, the browser will assume the default of Lax which is not the policy you need.
You need to explicitly set 'same_site' => "none", a value of none for same_site requires your connection to be secure, hence, set 'secure' => true.
'same_site' => "none"
'secure' => true
In my testing, it seems the session is not actually destroyed. However, it is not loaded when receiving the external POST request, and the session will be destroyed if you allow the return to the main site to trigger a new session save. By sending a header() redirect and terminating the process before a new session can be saved, it seems that it is possible to restore the existing session.
Okay, perhaps it's a bit gross?
Route::match(['get','post'],'/payment/confirmation','Payment\PaymentController#confirmation');
public function confirmation(Request $request)
{
// assert cookie or reload current URL
if (! $request->hasHeader('Cookie')) {
header('Location: '.url()->current());
exit;
}
$user = Auth::user();
dd($user); // user exists!
}
I'm not going to say this is a great solution. It does feel a bit hackish. Some additional testing may be required. But at first blush, it does seem to work — at least on my end. And maybe it gives some additional insight into what's actually going on behind the scenes.
Also, I'm not really sure whether you want to expose the payment confirmation page to a GET request.
But this was an interesting rabbit hole to go down for a bit.
You should keep your cookie session to 'lax', you don't want your cookies available on other sites, etc.
The fix as I have found is to pass true for remember when you do a login.
Example:
Auth::login(
user: $user,
remember: true
);
$request->session()->regenerate();
Your user will now be logged in indefinitely until they log out, ie going away from your site and returning via redirect headers and all that. I discovered this when using Passport to receive a callback for Oauth and I needed to log the user in at that point but redirect them to a subdomain for their tenant.
Normally you'll just want the session to be available across your root domain and subdomains like .mydomain.com in your config/env.

Laravel get redirect URL

I have problems with getting Laravel URL.
I have one page that if user is not logged in, it redirect user to wrong url and it's giving an error.
I'm using redirect()->intended($this->redirectPath()); to get back user where he was on page after login, so somehow I have to write code that will check what is the redirect URL, and if it's the URL that will give an error,
I know what is the URL, it must redirect user to another URL that I need to set.
I tried different methods taking
$this->redirectPath() == 'here goes the url'
and like
redirect()->intended($this->redirectPath()) == 'again url here'
But nothing works.
Try this:
return Redirect::intended('here goes the url');
Or
return Redirect::intended();
intended() checks if the session index url.intended exists and redirects to it by default or else redirect to $default='/' which can be overwritten.
You have to understand what redirect()->intended() actually does.
It looks for a session variable named url.intended like session()->pull('url.intended') (note that pull() will remove the variable after this call, which is handy because you usually only need this variable once).
This variable is currently only set when you call redirect()->guest('/yourpath') (it will set your current URL as the url.intended), unless you manually set it in your own logic using session()->put('url.intended').
So the most obvious way to use this is to use redirect()->guest('/login'), and then after the user has successfully logged in you may use redirect()->intended() (without parameter) to redirect the user back to the page that originally sent him to the login page.

How to remember which URL the user was accessing before registration

I am developing a Laravel application and I need some suggestion.
I have a page which when a user who is not logged in access, it redirects to the login page and after authentication, he is back to the same. This works fine.
The problem is that if the user was a new user. He doesnot have a login and goes for Registration.
He then registers and the application redirects him to several other pages (like e.g.He needs to verify his email) and when all is done he will be on the dashboard page.
Now is there any way, I can save that he was on certain page and after registering and moving through all those pages come back to the same page?
Thanks,
Santhosh
Since you haven't posted any code I'd write a general explanation of how I think you should handle this.
In short - you can get the indented url and add it to the registration button as a query parameter i.e yourdomain.com/register?origin=some_route.
So assuming you have a register button/link on your login page, add the origin to the link href:
<a href="register?origin=some_route">Register<a>
This way, when you finish the registration, you can simply access the origin by using \Input::get('origin').
Now, to actually get the intended url you can either try and get it from the Session by using:
\Session::get('url.intended', url('/'))
or you could use \Redirect::intended(url('/'))->getTargetUrl();
In both cases url('/') is used as a fallback url to the homepage and you could replace it with any other url you wish.
Hope this helps!
I imagine you could do something like this for one page:
return redirect()->intended('/dashboard');
which would the the same as
return \Redirect::intended('/dashboard');
As per docs: https://laravel.com/docs/5.2/authentication#authenticating-users
The intended method on the redirector will redirect the user to the URL they were attempting to access before being caught by the authentication filter. A fallback URI may be given to this method in case the intended destination is not available.
Alternately, if you're going through a multi-page login 'wizard' type deal, I'd personally store the initial value of redirect()->intended in a Session or Cookie, and redirect to the value of the session / cookie once your registration process is complete.
Instead of intended redirect function you can print the HTTP referer in a hidden field in the form, then after login redirect to that URL.
<input type="hidden" name="redirect" value="{{URL::previous()}}">
Controller:
if(Input::get('redirect') && (Input::get('redirect') != url('/path/to/login/'))){
return redirect(Input::get('redirect'));
}
else{
return redirect('/alternative/page');
}

Zend_framework - place data in $_POST when using _redirector helper in the controller

I an redirection (in some cases) from a controller to the error controller, action 'not-logged-in' using the redirector helper. My problem is the following: I want to pass an argument in the $_POST array (an URL from where the redirection happened) so the user will be able to return to that page after performing a login.
How can i place data in the $_POST array while using redirect helper?
Thank you ahead.
When you use the redirector with an internal redirect (ie. goToRoute) the paramters are passed along with it. Thus if you add your refferrer to the the request before you actually redirect:
// Assuming $request is a Zend_Controller_Request
$request->setParam('ref', $referrer);
// then use the redirector
then that variable will be passed along with the request upon redirect. So then you would need to check for/grab that variable from the request in the action youve redirected to and then set it as a hidden field in the form. Then when your form posts to your login action you can check again for a ref variable and on successful login redirect to that location.
Now if i were you i would not actually use the referral as the url but a serialized or json encoded array of the previous request's parameters. that way you can use goToRoute in this second instance as well.
Ofcourse if the redirection came form some sort of post action that contained sensitive data you wouldnt want to do this. In that case you would want to use the session as has been previously suggested.
Above all the best advice i can give is to look at the code of Zend_Controller_Router_Rewrite and Zend_Controller_Action_Helper_Redirector.
Not possible without some socket or Curl jiggery pokery.
Why not try using $_SESSION array in the same way?
Does it really matter if the user can see the redirection url in the address bar? i doubt they will care and i see it a few times on some top sites.
Passing control to the login page just feels more like a _forward than a _redirect, like it all belongs under the one action. Especially since you're coming right back.
_forward($action, $controller = null, $module = null, array $params = null)
Then, you can pass your originating location in $params as you'd like.
I'm pretty sure that you can't send POST when redirecting a person to another page. But maybe you can, and if so, I hope somebody proves me wrong here.
I'm not sure how you'd do what you want using Zend Framework, but I would suggest two ways how to do it in general. You can either send a GET variable, or use a session variable to store a back-URL.

Cakephp Session lost in Flash player

Just want to know if anyone have the same problem.
The website need to login to perform certain task. We use stock Auth component to do the job.
Everything is fine until it hits an interface which build in Flash. Talking to Amf seems fine. But when the Flash player try to talk to other controller - got redirect because the session in not presented.
So basically when a user login - I need to somehow find a way to login the Flash player in as well.
ADDITION:
This only solve half of the problem.
Backtrack a little bit. How the Auth components evaluate the requester?
If the Session.checkAgent is true. They check if its the last one. So Flash has no chance they have a different Agent string.
OK now - Auth check them out - what? The Session cookie they store earlier ... so fail again.
UPDATE
Thanks for all the answers.
I have tried the suggested solution. Only one problem.
I am using Amf (as Cakephp Plugins) when I tried to test if the $this->params['actions'] is start with amf - it works sometime doesn't work sometime. Looking at "Charles" I can see they all call to the amf controller. Very puzzling ....
in config/core.php
try
Configure::write('Session.checkAgent', false);
It appears that if you manage to call your Session->id($sessionId) before any call to Session->read(), Session->check() or Session->write(), you don't need to bother with all the destroy old session, update userAgent and delete cookie stuff.
use this in beforeFilter action of your controllere called by flash:
if ($this->action == 'flashCalledAction') {
Configure::write('Security.level', 'medium');
//Using instead the session specified
$this->Session->destroy();
$this->Session->id($_REQUEST['sessionId']);
$this->Session->start();
// We revert to the original userAgent because starting a new session modified it
$this->Session->write('Config.userAgent', $_REQUEST['userAgent']);
// We delete the flash cookie, forcing it to restart this whole process on each request
setcookie(Configure::read('Session.cookie'), '', time() - 42000, $this->Session->path);
}
then you have to pass these 2 params in each flash call to this controller:
param: 'userAgent' -> value: '$this->Session->read('Config.userAgent')'
param: 'sessionId' -> value: $this->Session->id()
http://blogs.bigfish.tv/adam/2008/04/01/cakephp-12-sessions-and-swfupload/
This is specifically for swfUpload but the process of appending the session_id to the urls and the settings for checkAgent and session security are covered and should help point you in the right direction.
Flash doesn't send the cookie along with its requests, that's why Cake doesn't log it in. The way I do it is: you need to somehow pass $this->Session->id() along with your flash requests. That is probably the hardest part because some flash application doesn't let you tag some info along in the request. Then write a component (FlashComponent, or whatever you want to call it) that check if it's a flash request, then look for the session id in its request and set the session id. You need to include this component before 'Auth': so var $components = array('Flash','Auth',...) to intercept the request before Auth does.
Or you can set Auth->allow list, but then you will expose these actions to non-authorization, and the action won't know who the current logged in user is (unless you can pass something in the flash request, in that case, use my first solution).

Categories