Laravel Nova Redirect to a custom path after login - laravel-nova

I need to redirect user after login to a different place according to its role.
The logic is simple. I tried to put it in redirectPath() function in Nova LoginController.php, but I have a very weird behavior - sometimes after login I reach the right place, sometimes Nova redirects me to panel.
Any idea?

After a couple of hours of investigation, I figured out that the solution is quite simple.
All I had to do is to add the following function to nova LoginController:
protected function sendLoginResponse(Request $request)
{
$request->session()->regenerate();
$this->clearLoginAttempts($request);
$redirectPath = $this->redirectPath();
redirect()->setIntendedUrl($redirectPath);
return redirect()->intended($redirectPath);
}
Explanation:
This function is implemented in trait AuthenticatesUsers.
intended function (member of Redirector class) create a redirect response, based on previously intended location, and if not exists - on given url.
If no url.intended is set in session, user will be redirected to url generated by LoginController::redirectPath. However, if there an entry of url.intended does exist in session, we need to delete it in order to force redirecting user to the url we are interested in.
The only problem which I see is that we loose the feature of redirecting user to the same page he was before he was logged out. So it is a simple matter of choice as a developer...

Related

Is it possible to resolve navigation outcome in order to validate it?

I've got a WebFilter that redirects to the login page in my application. In order to redirect back to the referring page I've also added a view parameter called redirectOnLogin which is then used on successful logins in order to perform the final navigation.
If one were to manipulate this query parameter, one could easily provoke JSF navigation errors. I would therefore like to pre-empt this by checking that the outcome is valid but I've not been able to uncover a mechanism for pre-validating a JSF outcome.
Easiest and best is to make sure the redirectToLogin parameter cannot be manipulated. Or that manipulation is detected.
You could solve this in (at least) two ways
Taking the original page name, adding a 'salt' to it and creating a hash.
Addin this has that in the request to the login server
Make sure it is returned by the login server (maybe adding it as # to the return page or as a param.
On receiving it on the 'redirectOnLogin' page, use the page name, the same salt and create a hash in the same way. Compare these and if they match you are fine, if they don't throw an error.
Or you could
Store the 'redirectOnLogin' page in a session to
Check on returning from the login server if it matches with the page you end-up on.

URL: Include a parameter inside a destination query

I've searched a lot to try and solve this problem, but I'm not quite sure what to search for. I didn't really manage to find anything.
Essentially I'm working on a website in which users can register for an event. However, if the user is not logged in, I need to redirect them to the registration screen. This much I've been able to accomplish without much difficulty. However I need to redirect back to the event that they attempted to register for.
My real problem is that the URL of the page I need to return to contains an a parameter, and I'm not sure how to make the registration page take that parameter into account when it redirects back.
Currently when an anonymous user tries to go to
http://[...].com/drupal/?q=civicrm/event/register&id=6
I have it redirect you to
http://[...].com/drupal/?q=user/register&destination=civicrm/event/register&id=6
However, once the form is submitted the "&id=6" is not taken as part of the destination parameter, which means you just go to.
http://[...].com/drupal/?q=civicrm/event/register
Which is not a valid page.
Is there a way for me make the destination parameter include "&id=6"?
On a whim I've also tried.
[...]destination='civicrm/event/register&id=6'
[...]destination="civicrm/event/register&id=6"
[...]destination=civicrm/event/register#id=6
You need to url-encode the value for your destination. Try this:
[..]destination=civicrm/event/register%3Fid%3D6
%3F is hex code for question mark (?), %3D is code for equals (=).

ASP.NET MVC, BDD, Specflow and WatiN: putting the application in a specific state

I'm new to BDD, Specflow and WatiN. I would like to use these tools to automate acceptance tests for my ASP.NET MVC application.
I've already figured out how to basically use these tools, and I successfully built my first acceptance test: Log on to the website.
Here is the Gherkin for this test:
Feature: Log on to the web
As a normal user
I want to log on to the web site
Scenario: Log on
Given I am not logged in
And I have entered my name in the username textbox
And I have entered my password in the password textbox
When I click on the login button
Then I should be logged and redirected to home
Now, I would like to write a bunch of other tests, and they all require the user to be authenticated. For example:
Feature: List the products
As an authenticated user
I want to list all the products
Scenario: Get Products
Given I am authenticated
And I am on the products page
When I click the GetProducts button
Then I should get a list of products
What bugs me is that to make this test independent of the others, I'd have to write code to log on the website again. Is this the way to go? I doubt.
I'm wondering if there are best practices to follow for testing scenarios like that. Should I keep the browser open and have the tests run in a specific order, on the same browser? Or should I put the MVC application in a specific state?
For this, we have a specific Given step, that looks something like this in Gherkin:
Given I am signed in as user#domain.tld
Like you mentioned, this step basically reuses other steps to sign in the user. We also have an "overload" that takes a password, in case the test user has a non-default test password:
Given I am signed in as user#domain.tld using password "<Password>"
[Binding]
public class SignInSteps
{
[Given(#"I am signed in as (.*)")]
public void SignIn(string email)
{
SignInWithSpecialPassword(email, "asdfasdf");
}
[Given(#"I am signed in as (.*) using password ""(.*)""")]
public void SignInWithSpecialPassword(string email, string password)
{
var nav = new NavigationSteps();
var button = new ButtonSteps();
var text = new TextFieldSteps();
var link = new LinkSteps();
nav.GoToPage(SignOutPage.TitleText);
nav.GoToPage(SignInPage.TitleText);
nav.SeePage(SignInPage.TitleText);
text.TypeIntoTextField(email, SignInPage.EmailAddressLabel);
text.TypeIntoTextField(password, SignInPage.PasswordLabel);
button.ClickLabeledSubmitButton(SignInPage.SubmitButtonLabel);
nav.SeePage(MyHomePage.TitleText);
link.SeeLinkWithText("Sign Out");
}
}
I think this is the best approach, since you should not be able to guarantee that all of the tests run in a specific order.
You may also be able to do this with a SpecFlow tag though, and have that tag execute BeforeScenario. That might look something like this:
Feature: List the products
As an authenticated user
I want to list all the products
#GivenIAmAuthenticated
Scenario: Get Products
Given I am on the products page
When I click the GetProducts button
Then I should get a list of products
[BeforeScenario("GivenIAmAuthenticated")]
public void AuthenticateUser()
{
// code to sign on the user using Watin, or by reusing step methods
}
...should I put the MVC application in a specific state?
When signing in users, it's not the MVC application that needs to be put into a specific state, but rather the browser that needs to be put into a specific state -- namely, writing the authentication cookie. I'm not sure if you can do this or not, given that the auth cookie is encrypted. I always found it easier to just let SF walk though the authentication steps at the beginning of each scenario.
You might want to consider further refining your solution. Have a read of Dan North's Who's Domain is it anyway and then ask yourself if these two scenarios actually belong together. I've found there is value in the approach that danludwig has suggested, but there's more value in separating your scenarios according to their domain. Think of it as refactoring your scenarios.
You can still build one scenario from the activities of another, but ask yourself, do you really need to go through the same steps, or would providing a mocked "Already logged in" object to your session work better.

How often is a Facebook Connect session refreshed?

I have set up Facebook Connect on my site, and the login is working fine. I have set up a listener to detect a login state change, as follows:
FB.Event.subscribe('auth.sessionChange', function() {
window.location.reload();
});
All good. Except that leaving a browser window open causes the page to reload after perhaps 20mins. So the auth.sessionChange is firing at some interval. Which can caused havoc, particularly if the last page was a POST form submission.
In the FB docs it says "Sessions are refreshed over time as long as the user is active with your app." How often is this session refreshed?
And how can I protect the page from reloading if it doesn't need to? A conditional maybe within that function??
EDIT - adding information for clarification:
I thought I would add some info to give those offering the advice some more to go on (thanks so far BTW):
the reason I have the listener triggering a reload is because I wanted users to be logged in to the site every time they visit - if they already had a session in FB. I was detecting an active session with the JS SDK, which I know could do log in on its own, but I needed to trigger a page reload after the JS had done the detection, in order to set a PHP session for the site - required step. I couldn't do the PHP login without first letting the JS detect the FB session in the browser.
Usually you can see the length of the validity of the session just by looking at the session itself. However in many cases, I suggest requesting the offline_access permission to ensure the access_token remains valid as long as the user doesn't change their password and doesn't remove your application.
Andy, if you are only listening for login state then subscribe to auth.login and auth.logout instead of auth.sessionChange.
If you need an active session for a user to take an action on your site, use FB.getLoginStatus() or FB.getSession() to check the session object.
http://developers.facebook.com/docs/reference/javascript/FB.getLoginStatus/
http://developers.facebook.com/docs/reference/javascript/FB.getSession/
It really depends on your App work-flow and the below is just a general approach.
You can have a flag that presents in all your pages (maybe in your main layout if you are using a template system) with a setter function to be executed once you don't need a page reload to happen. Something like:
var do_reload = true; // By default, we always allow a reload
FB.Event.subscribe('auth.sessionChange', function() {
if( do_reload ) {
window.location.reload();
}
});
// Call this whenever you don't want 'auth.sessionChange' to reload the page
function turnoff_reload() {
do_reload = false;
}
// Call this to return to default behavior
function turnon_reload() {
do_reload = true;
}
Now if you are "redirecting" the user (e.g.: after a form post) to a page that doesn't require a reload then you need to set the flag in the first line to false.
Another scenario if you have an ajax loaded content based on the user interaction, if the page reloads by itself that content will be lost and the user needs to interact again to view that content, what can be done here is setting the flag to false after the Ajax call.

Symfony doctrine admin generator list filters get method with no csrf token

EDIT: The solution turned out to be along these lines:
public function executeIndex(sfWebRequest $request)
{
if ($request->getParameter('first_name')) {
$this->setFilters(array('first_name' => $request->getParameter('first_name')));
}
parent::executeIndex($request);
}
Hi,
So, I've just started using symfony admin generator and it's great. But, I want to know, how I can I filter the lists using a GET request? e.g. /users?name=Simon
If I try: /users/filter/action/users[name]/Simon
It complains there is no CSRF token, because usually you filter by using the filter form it generates for you.
All I want to do is create links from one list to the other. e.g. clicking "See this User's Posts" in each user list record will send you to the Posts screen but with it filtered by this user.
I wouldn't be surprised if this could actually be done by the generator.yml but I don't know how, yet.
Thanks in advance for any assistance you can provide.
My answer here explains what you need: symfony - admin module filters accessible as links
I have tried embedding the filter form of the "target" table in the main table from which you would like to be redirected hidding everything but the filter button. As you have mentioned it does not always work without the token.

Resources