Ok, here is the requirement.
I want to build a system look like this:
- Header: have a PleaseLoginPanel and SuccessfulLoginPanel
- Content Page just contains content & communicate with header via EventBuss
- HeaderPresenter is the parent presenter & ContentPresenter is nested inside the Header presenter.
Let say when user opens this url "mydomain#content" they will see a page that has header contaning PleaseLoginPanel on top & a content part (beneath the header) contaning some textarea and button for user to input data and submit to DB .
To be able to access the widget in content page the user need to login, after logged in, the PleaseLoginPanel will be invisible and the SuccessfulLoginPanel will be visible. User now can play with widgets in content part.
Let say Session & Cookies will last 1 hour, after the session cookies expired the user can not submit the content data.
Let say user spent a lot of efforts to prepare data & about to submit but the session expired so he can't submit. At that time, in the header the SuccessfulLoginPanel still stay there. So the user can lose all his content he prepared before. You may say, he can open a new page & login & copy the data from the old page (the page that has session expired & does not have PleaseLoginPanel), but that still cost him a lot of effort to copy over.
So I want that, when the Cookes has just expired it will fire an Event to the Header & ask the header to show the PleaseLoginPanel
How can we do that in GWT or GWTP?
Found a solution that is to use timer
Timer showLoginPanelTimer = new Timer() {
public void run() {
getView().getLoginPanel().setVisible(true);
getView().getSuccessfulLoginPanel().setVisible(false);
getView().getEmailBox().setText("");
getView().getPasswordBox().setText("");
Utility.removeUserInfoCookies();
}
};
showLoginPanelTimer.schedule(Utility.COOKIE_TIMEOUT);
Related
This question already has answers here:
Prevent user from seeing previously visited secured page after logout
(7 answers)
Closed 6 years ago.
I have a JSP page with a form where you fill up certain details. On submitting the form i call a servlet which then updates details in a database after that i redirect to a page i display a confirmation message to the user.
The problem i have here is when the user clicks back he goes to the form page again where if he clicks a submit button, it creates a new record in the database.
Consider this similar to a shopping cart example where in this case he would buy the same item twice. But the only problem here is i cannot handle this in backend, i.e. the database can never know a redundant operation is taking place.
I need to handle this from the client side.Bit weird but i have to do it this way.
Basically when the user clicks the back button i don't want him to be able to go to the form page and may be just to some other page.
This is a typical HTML form issue, you can solve it through any one of following methods
1) Server side (page expiration): Since you've mentioned that the page refreshes and goes to the confirmation. You can set no-cache and add a page expiration time as -1 to the page you have that form.
So that when user presses the back button, he will see that the page has expired. He will be forced to load the page freshly. This is the behavior that I see in most banking websites.
Response.Buffer = True
Response.ExpiresAbsolute = Now() - 1
Response.Expires = 0
Response.CacheControl = "no-cache"
2) Using turn Key method: When the form loads, you can generate a random key in session memory and also embed it as a hidden value in the page.
During form submission, check the submitted hidden key against the value in session. If exists, then add the entry to database otherwise you can reload the page with a fresh key for the user (who might have done that unintentionally).
In load balanced or web farms, consider persisting the turn key in Database against the current user.
3) Client Side (Not recommended) : You can restrict the user from using the browser back button by removing the page from the history. (One side effect is that it will remove the entire history for that browser tab/window)
history.pushState(null, null, document.title);
window.addEventListener('popstate', function () {
history.pushState(null, null, document.title);
});
If you need the same support for older browsers where push and pop states are not supported, you can use following snippet.
<script>
function preventBack() {
window.history.forward();
}
setTimeout("preventBack()", 0);
window.onunload = function() {
null
};
</script>
Before redirecting to the JSP page send these headers with the response from the controller so that the page is not stored in cache and the browser will always request a new page from the server.
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
response.setHeader("Pragma", "no-cache"); // HTTP 1.0.
response.setDateHeader("Expires", 0);
So every time you go back to that page a new page will be requested from the server and will be displayed with the cleared input fields.
You could implement a PRG-Pattern (https://en.wikipedia.org/wiki/Post/Redirect/Get) using php.
Basically, after successfully submitting the form you redirect to a confirmation page which informs the user that their submission was successful/accepted/etc. and also set a variable which you can later use to check if said submission has been submitted yet.
When the user tries to reload said page or go back you can check the variable and display either the form again or the confirmation page based on if the submission has been submitted already.
I think following flow is the best:
Client submits data to server
Servlet processes it
It returns HTTP 303 redirect to client
Client redirects to success page
After this flow, refresh, back button will work properly.
For more information read Simple Post-Redirect-Get code example
In my Vaadin webapp I have a tipical architecture with login. In some cases, the user can access directly to some resources using Vaadin URI Fragments (http://example.com/#fragment).
When a user tryes to access some resource, If the user has logged in, I take from the URL the #FRAGMENT and I bring him to it.
But if the user has no logged in, when he logs in I used to bring him to the main page using
getPage().open("/", "_self");
but since if I add an URI Fragment, the getPage().open(...) does not work.
Is there any way to redirect the user to a correct URL (URL with UriFragment in my case) from code?
Note that there is a fundamental difference in how navigation is handled in traditional web applications versus single-page applications as implemented with Vaadin. In traditional web applications you navigate through the app by making full HTTP GET-Requests on some path (such as www.example.com/myapp/home). On each such request, a full page reload is performed. You can't do that with Vaadin, as a full page reload means reloading the Vaadin widget set and rebuilding the page layout from the ground up. Therefore, single-page applications typically use the URI fragment for navigation purposes. Changes to this fragment are solely handled by the client-side JavaScript code. There will be no GET-Request induced by the browser when the URI fragment is changed.
That's why the approach you described doesn't work for you. Using Page.open(...) will open a web page through a HTTP GET-Request resulting in a complete reload of your Vaadin application.
The solution for your problem is to solely handle all navigation (including state-dependent redirects) through the Page object's URI fragment handling methods (or through the [Navigator][1] component). Redirecting in Vaadin can be achieved by programmatically setting the URI fragment with Page#setUriFragment() or Navigator#navigateTo() and having your URI handling code (or Navigator) take care of the rest. Only then it is assured that your users stay on the same page even when they are redirected to a login form or to some other place after logging in.
I would like to add to Roland's answer and share how I solved this.
My UI:
#Override
protected void init(VaadinRequest request) {
setSizeFull();
setContent(masterView);
getPage().addUriFragmentChangedListener(event -> present(event.getUriFragment()));
present(getPage().getUriFragment());
}
The masterView is just a CustomComponent that has a content section. When the menu is clicked, I simply setContent to the masterView's content section. Swapping out the middle, basically.
present method:
private void present(String fragment) {
masterView.setContent(getComponentFromFragment(fragment));
}
Finally:
private Component getComponentFromFragment(String fragment) {
if (fragment.equals(someOtherView.NAME))
return someOtherView;
return null; // null clears it out as in the welcome page
}
The important part is the present in the init. When the UI renders for the first time and fires the init, it goes ahead and grabs whatever the URI fragment is in the browser and presents that as well.
Works great.
Maybe this can work:
UI.getCurrent().getPage().executeJavaScript("window.location.href = 'http://google.com'");
I am using GWT 2.5.1.
In my GWT web app I have a ComplexPanel object which contains a set of fields(widgets). There are a suggested field (on panel) which gives me the opportunity to find object and info about it. Fields (10-15 of them) contain info about that object.
The problem is when user (client side) has a slow internet connection, fields on form are updated with a delay. And if in moment of delay user click 'Save' button (AsyncCallback), old data (which is not updated) posted to the server.
How it works:
1. Server receive callback from the form and start to processing the data.
2. Server refresh all the fields with new data and end the works.
3. Javascript updating the data on form using about 10 requests.
But: internet is slow and one part of data is refreshed and other no.
4. User click SAVE and mixed data goes to the server.
I need to know (from server side) when all the field are refreshed on client side and server can proceed with a next post request.
Thanks in any advice.
Perform a validation check on click of the save button. There are several things you can do as per your requirement. I have listed one way to validate it.
Set a flag before making the async call as false. For instance, isLoaded = false
Once you have all the fields just update it to true, i.e. isLoaded = true
On save button handler check for isLoaded flag. If false, prompt a message, else save.
Update:
You can count the number of response received. You know that you will get 10 response. So for every response received increment a counter. Activate save only if you have all 10 response recieved.
For a clean way to do this, use gwt-async-future.
Page one contains an HTML form. Page two - the code that handles the submitted data.
The form in page one gets submitted. The browser gets redirected to page two. Page two handles the submitted data.
At this point, if page two gets refreshed, a "Confirm Form Resubmission" alert pops up.
Can this be prevented?
There are 2 approaches people used to take here:
Method 1: Use AJAX + Redirect
This way you post your form in the background using JQuery or something similar to Page2, while the user still sees page1 displayed. Upon successful posting, you redirect the browser to Page2.
Method 2: Post + Redirect to self
This is a common technique on forums. Form on Page1 posts the data to Page2, Page2 processes the data and does what needs to be done, and then it does a HTTP redirect on itself. This way the last "action" the browser remembers is a simple GET on page2, so the form is not being resubmitted upon F5.
You need to use PRG - Post/Redirect/Get pattern and you have just implemented the P of PRG. You need to Redirect. (Now days you do not need redirection at all. See this)
PRG is a web development design pattern that prevents some duplicate form submissions which means, Submit form (Post Request 1) -> Redirect -> Get (Request 2)
Under the hood
Redirect status code - HTTP 1.0 with HTTP 302 or HTTP 1.1 with HTTP 303
An HTTP response with redirect status code will additionally provide a URL in the location header field. The user agent (e.g. a web browser) is invited by a response with this code to make a second, otherwise identical, request to the new URL specified in the location field.
The redirect status code is to ensure that in this situation, the web user's browser can safely refresh the server response without causing the initial HTTP POST request to be resubmitted.
Double Submit Problem
Post/Redirect/Get Solution
Source
Directly, you can't, and that's a good thing. The browser's alert is there for a reason. This thread should answer your question:
Prevent Back button from showing POST confirmation alert
Two key workarounds suggested were the PRG pattern, and an AJAX submit followed by a scripting relocation.
Note that if your method allows for a GET and not a POST submission method, then that would both solve the problem and better fit with convention. Those solutions are provided on the assumption you want/need to POST data.
The only way to be 100% sure the same form never gets submitted twice is to embed a unique identifier in each one you issue and track which ones have been submitted at the server. The pitfall there is that if the user backs up to the page where the form was and enters new data, the same form won't work.
There are two parts to the answer:
Ensure duplicate posts don't mess with your data on the server side. To do this, embed a unique identifier in the post so that you can reject subsequent requests server side. This pattern is called Idempotent Receiver in messaging terms.
Ensure the user isn't bothered by the possibility of duplicate submits by both
redirecting to a GET after the POST (POST redirect GET pattern)
disabling the button using javascript
Nothing you do under 2. will totally prevent duplicate submits. People can click very fast and hackers can post anyway. You always need 1. if you want to be absolutely sure there are no duplicates.
You can use replaceState method of JQuery:
<script>
$(document).ready(function(){
window.history.replaceState('','',window.location.href)
});
</script>
This is the most elegant way to prevent data again after submission due to post back.
Hope this helps.
If you refresh a page with POST data, the browser will confirm your resubmission. If you use GET data, the message will not be displayed. You could also have the second page, after saving the submission, redirect to a third page with no data.
Well I found nobody mentioned this trick.
Without redirection, you can still prevent the form confirmation when refresh.
By default, form code is like this:
<form method="post" action="test.php">
now, change it to
<form method="post" action="test.php?nonsense=1">
You will see the magic.
I guess its because browsers won't trigger the confirmation alert popup if it gets a GET method (query string) in the url.
The PRG pattern can only prevent the resubmission caused by page refreshing. This is not a 100% safe measure.
Usually, I will take actions below to prevent resubmission:
Client Side - Use javascript to prevent duplicate clicks on a button which will trigger form submission. You can just disable the button after the first click.
Server Side - I will calculate a hash on the submitted parameters and save that hash in session or database, so when the duplicated submission was received we can detect the duplication then proper response to the client. However, you can manage to generate a hash at the client side.
In most of the occasions, these measures can help to prevent resubmission.
I really like #Angelin's answer. But if you're dealing with some legacy code where this is not practical, this technique might work for you.
At the top of the file
// Protect against resubmits
if (empty($_POST)) {
$_POST['last_pos_sub'] = time();
} else {
if (isset($_POST['last_pos_sub'])){
if ($_POST['last_pos_sub'] == $_SESSION['curr_pos_sub']) {
redirect back to the file so POST data is not preserved
}
$_SESSION['curr_pos_sub'] = $_POST['last_pos_sub'];
}
}
Then at the end of the form, stick in last_pos_sub as follows:
<input type="hidden" name="last_pos_sub" value=<?php echo $_POST['last_pos_sub']; ?>>
Try tris:
function prevent_multi_submit($excl = "validator") {
$string = "";
foreach ($_POST as $key => $val) {
// this test is to exclude a single variable, f.e. a captcha value
if ($key != $excl) {
$string .= $key . $val;
}
}
if (isset($_SESSION['last'])) {
if ($_SESSION['last'] === md5($string)) {
return false;
} else {
$_SESSION['last'] = md5($string);
return true;
}
} else {
$_SESSION['last'] = md5($string);
return true;
}
}
How to use / example:
if (isset($_POST)) {
if ($_POST['field'] != "") { // place here the form validation and other controls
if (prevent_multi_submit()) { // use the function before you call the database or etc
mysql_query("INSERT INTO table..."); // or send a mail like...
mail($mailto, $sub, $body); // etc
} else {
echo "The form is already processed";
}
} else {
// your error about invalid fields
}
}
Font: https://www.tutdepot.com/prevent-multiple-form-submission/
use js to prevent add data:
if ( window.history.replaceState ) {
window.history.replaceState( null, null, window.location.href );
}
I want to know the difference between :
$this->forward("module", "action");
And
$this->redirect("module/action");
My first guess is that one implies a new request while the other one not, but I'm not sure.
In some cases, the action execution ends by requesting a new action execution. For instance, an action handling a form submission in a POST request usually redirects to another action after updating the database. Another example is an action alias: the index action is often a way to display a list, and actually forwards to a list action.
The action class provides two methods to execute another action:
If the action forwards the call to another action:
$this->forward('otherModule', 'index');
If the action results in a web redirection:
$this->redirect('otherModule/index');
$this->redirect('http://www.google.com/');
The choice between a redirect or a forward is sometimes tricky. To choose the best solution, keep in mind that a forward is internal to the application and transparent to the user. As far as the user is concerned, the displayed URL is the same as the one requested. In contrast, a redirect is a message to the user's browser, involving a new request from it and a change in the final resulting URL.
If the action is called from a submitted form with method="post", you should always do a redirect. The main advantage is that if the user refreshes the resulting page, the form will not be submitted again; in addition, the back button works as expected by displaying the form and not an alert asking the user if he wants to resubmit a POST request.