In the personal account, the user can create a new advertisement, and it will be displayed in the "Draft" block.
In order for the ad to become active, it must be sent for moderation to the administrator. As soon as the user clicks the submit button, the ad changes its status and gets into the "On Moderation" block
I decided to put the process of changing the status of the ad in the queue according to the instructions from the documentation https://symfony.com/doc/current/messenger.html
In the right place in the controller I do the following
$bus->dispatch(new ChangeStatus($ad))
return $this->redirectToRoute('user_cabinet', ['id' => $user->getId]);
After sending an advertisement for moderation, a redirect to the page with all ads should occur. The redirect happens, the status of the ad also changes to the correct one, but the ad itself is still hanging in the "Draft" block. In order for it to get into the "On Moderation" block, I have to additionally reload the page. Although when sending for moderation, the page reloaded.
Maybe I'm not using the right tool for this task or I don't understand something?
Related
I need to make the client to navigate through a series of redirects. After the user arrives to the destination, I'd like to allow the user to go back to an intermediate page to be redirected elsewhere.
For example, take the following diagram:
Current Page -> Processing Page -> Landing Page
Status: 3XX
|
V
Alternative Page
Disclaimer: I do not have control over Landing Page but I do have control over the others.
From the Current Page, the user is sent to the Processing Page which, after checking the DB, redirects the user to the Landing Page. What I would like is, if the user presses the back button, to be sent back to the Processing Page so it can redirect the user to the Alternative Page.
The problem is that, because of the 3XX status code, the Processing Page is never injected into the browser's history so when the users goes back, they are sent to the Current Page directly.
So far, I've achieved my goal by making Processing Page to return 200 and force a redirect via JS as the first thing but it feels like a clunky solution.
Would it be possible to achieve the same outcome with a combination of HTTP headers? Another solution, since I have control over Current Page is to place the decision making algorithm there but this is a complex enough page already that I'd rather prefer to avoid this option.
Many thanks!
I've encountered a weird situation, after registration we're sending an email with a verification link, pretty standard stuff, but somehow clicking on the link seems to make the request twice, looking at the logs, the first time it comes from my IP and the second request comes from some Google IP: 66.102.8.60 (doing a reverse lookup shows google-proxy-66-102-8-60.google.com).
Any idea what's going on and how to prevent this?
The server is running Nginx and the site is Ruby on Rails if that helps.
I do not know the root cause but my best guess is same as Tripleee wrote above - most probably google is scanning urls. This happens in all browsers (well at least in Chrome and Firefox), but only under following circumstances:
the url is clicked from gmail (if you copy paste it to browser tab, the second request is not issued)
the url is clicked for the first time... Subsequent clicks from the same email do not trigger second request
I know it is probably not the answer you expected, but after giving it some thought I figured that operation like this should be handled on server side. In my case I am tracking information about confirmation urls anyways, so the first time the request comes to my backend I am deleting it and proceeding with confirmation normally. Since the confirmation entry is missing in the database for the second request it returns immediately with status 404, 422 or something whatever suits you.
Hope that helps anyone who gets here looking for an answer to this problem ;)
I'm making a "browser game" in Symfony2 (like an RPG). There's a moment when you start a battle, and you can't do anything else until the battle is over.
I need to check, when a user have an status like "In battle" wherever URL he is trying to reach, redirect to the "battle page".
I tried with an EventListener to Kernel.Request, and check every time when that user have the BATTLE status AND is not in the Battle Page redirect there. That doesn't work well because I have a lot of request and things I have to exclude like DebuggerToolbar, etc..
There's a proper way to do this? Maybe special add an special role/permission? Check on every controller? in the action?
I'm sure there's a good way to do this but I don't know how to look for it.
Thanks!.
You can do it by listening to the kernel.controller event and throw an error when the condition is not met to execute that controller with a specific exception.
Create an exception listener that will execute the redirect when intercepts that specific exception.
A very good description of the mechanism you can read here: http://php-and-symfony.matthiasnoback.nl/2012/12/prevent-controller-execution-with-annotations-and-return-a-custom-response/
This question is a question about login flows for web-apps in general. I'm most interested in answers that optimize for usability and performance while maintaining security.
What is the most appropriate way to handle unauthenticated requests to bookmarked URLs?
To demonstrate the problem, here are some routes and respective behaviors for an example application:
GET /login -> Display the authentication form
POST /processLogin -> process the username and password,
if unauthentic...re-render the login form;
otherwise...display the default page
GET /secret -> if authenticated...display the secret resource;
otherwise...display a login form
POST /secret -> if authenticated...perform a desirable, but potentially
non-idempotent action on the secret
resource
otherwise...display a login form
Option 1: Display login screen, redirect to desired page
User clicks bookmark
GET /secret -> 200, surreptitiously display login form with hidden field path="/secret"
POST /processLogin -> 302 to /secret (value of path parameter)
GET /secret -> 200, secret resource displayed
Analysis: Hopefully, your client is a modern browser, non-compliant with HTTP, such that it performs a GET after a 302'd POST. This applies across the board. Should I be worried?
Option 2: Redirect to login screen, redirect to desired page
User clicks bookmark
GET /secret -> 302 to /login
GET /login via redirect -> 200, login form displayed with hidden field path="/secret"
POST /processLogin -> 302 to /secret
GET /secret -> 200, secret resource displayed
Analysis: Same problems as above. Added problem that the URL displayed by the browser during login changes, which is confusing to the user and breaks bookmarking, link sharing, etc.
Option 3: Display login screen, display desired page
User clicks bookmark
GET /secret -> 200, surreptitiously display login form with action="/secret"
POST /secret -> 200, secret resource displayed
Analysis: Sadly, the refresh button is now also broken: refresh will cause the user agent to re-POST with a warning, instead of re-GETing /secret. They user gets a warning, but if they ignore it, something bad happens.
On the bright side, you minimize roundtrips with this technique.
Option 4: Redirect to login screen, display desired page
User clicks bookmark
GET /secret -> 302 to /processLogin
GET /processLogin via redirect -> 200, login form displayed with action="/secret"
POST /secret -> 302 to /secret
GET /secret -> 200, secret resource displayed
Analysis: Same problems as options 2+4.
Option 5: ???
Is there another technique I'm missing?
In general, which of these techniques would you recommend?
See Also
What is correct HTTP status code when redirecting to a login page?
What kind of HTTP redirect for logins?
HTTP response with redirect, but without roundtrip?
Option 1 & 3 are not following the HTTP RFC as "surreptitiously display login form" contradicts 200 GET response, where "an entity corresponding to the requested resource is sent in the response" is expected.
Option 2 is OK. All modern browsers support 302 on POST and many REST-based frameworks (like RoR) actively use it. Alternatively in "302 to /login" you can already create the session (cookie) and store the URL in session, to avoid passing the original URL in GET parameters. From usability standpoint, you can have an appropriate message on login page too (I think the URL mismatch is irrelevant here - you can't let the user see the content anyway).
Option 4: when you POST to /secret, HTTP RFC expects you to "accept the entity enclosed in the request as a new subordinate of the resource identified by the Request-URI in the Request-Line", but all you are doing is logging in and not creating anything new under /secret.
So following HTTP RFC, your best choice is Option 2. Actually Option 2 is also in line with POST->Redirect->GET design pattern, which helps to address the issue of unpredictability in bookmarking URLs to POST'ed resources.
My $.02: I recently implemented using option 2 (although I stored /secret in a session, not in the login form as a hidden field).
I don't entirely share your concerns:
Added problem that the URL displayed
by the browser during login changes, which is confusing to the user
and breaks bookmarking, link sharing, etc.
Redirecting to /login, and the subsequent change of URL, tells the user that before they can continue there's something else that needs to be done first: logging in.
Since a login page will look entirely different from the 'target page', I don't see how that will confuse people into bookmarking and/or link sharing the login page instead of the target page (since the login page won't contain the information they want to bookmark/share anyway).
And if you're worried about 302's breaking the standard (although every single browser I know will happily break it), consider using 303's instead.
Note that mickeyreiss is correct, using AJAX Option 3 works without the drawback of the broken back button. However, it means the user has to have JavaScript enabled. This being said, if you program your form properly, you can detect whether JS is present, if not use Option 1.
Note that the 302 response is fine, however, you may have problems with caches. You have to make sure that nothing gets cached if you want to show 2 completely different pages/forms on for the same URI. (/secret showing the login and then the actual secret.)
I almost always use option #2, simply because the content returned by a URL is consistent. While today's secrets are hidden behind a login, tomorrow you may want to open it up or display mixed public/secret depending on authentication at the same URL. In that case, option #2 will be most like what Google would expect. Any content bait and switch is looked down on by Google and in the extreme case, all of your pages would have duplicate page content (ie. login form).
I would choose the option using AJAX:
login page and hide the content
the user enters the login and the password.
Authentication is done in the server side.
The server returns a result
if successful use location.href to set the page you would like to
go to, or else you can output a message saying the login is not
valid.
In your server you will be testing on a _SESSION variable, if not set redirect to the login page..
What whould be the best way to prevent multiple users on a page?
For example if a user is at the page "Home.aspx", no other users should be allowed to go there.
I'm using asp.net on the server and the js-frameword jQuery on the client side.
The easy part is only allowing one user to access a page. You can for example store a session id in an application variable to keep track of who's on the page.
The hard part is to know when the user leaves the page. The HTTP protocol only handles requests, so the server only knows when a user enters the page. There is no concept of "being on" a page in the protocol.
You can use the onunload event in client code to catch when a user goes somewhere else, however this will not always work. If the user loses the internet connection, there is no way to communicate back to the server that the user leaves the page. If the browser or computer crashes, there will naturally be no onunload event.
You can keep requesting data from the server, by for example reloading an image on the page. That way the server can know if the user is still on the page at certain intervals. However, if the user loses the internet connection, the server will think that the user has left, while the user thinks that he/she is still on the page.
Another problem is browser history and cache. A user might leave the page, then go back to the page again. You have to make sure that the page is not cached, or the browser will just use the cached page and the server has no idea that the user thinks that he/she is on the page again.
Agreed with Guffa, you cannot be sure that the browser is already on the page or not, you can only check if the browser is already connected to that page or not.
You can do a sort of "ping", but its more a trick than a 100% working solution and it requires javascript enabled.
I didn't do it but I should look at XMLHTTPRequest and onreadystatechange to handle this :
1) On page load, the browser (client) initiate a XMLHTTPRequest with the web site (server) then wait for callback with the onreadystatechange event.
2) The web site receive the request and "mark" the page as "in use" with the current DateTime.Now.
3) Then the web site sends the response.
4) The onreadystatechange event get the response and the event code re-request the server to re-initiate the 2 after 1 min.
5) If another client request the page, the server check the DateTime mark : if the mark is greater than 1min ago, it means the client didnt respond to the request and may not be on the page again.
Not sure why you would want to do this because it flies in the face of web usability. You could do a locking mechanism on each page in server side code (write user name, page and time to a DB), which is freed up when they go to another page. You would then check on a the page load event to find out if anyone currently has that page locked. However, and this is a big however - have you considered what happens if somebody just shuts their browser down or walks off and leaves it on a page. You would need to seriously consider a timeout to free up locks too. That would need to be a back ground service, either in global.asax as global code or a separate process.
Maybe use static variables to hold the ip of the first user to access the page and then check whether other requests come from the same ip, otherwise display a "no access" page.
make sure you use lock it:
Object thisLock = new Object();
lock (thisLock)
{
// access static variables
}
You should also use "Session_End" method in global.asax to remove the ip address in case the user leaves your website without pressing the logout button