3

I use Spring Security to deal with session timeout. My application also uses AngularJs.

I have the following issue:

If the session times out and a user issues a non-ajax request from an angularJs page to a secured url, Spring Security redirects me to the login url but keeps the part of the Url after the # (hash) sign.

Let me illustrate:

  • A user is located at /myapp/foo#!/bar
  • Session times out
  • User issues get request to secured url
  • User is redirected to /myapp/signin#!/bar

How can I avoid the #!/bar part from being added to signin page?

Edit: There is a slight mistake in the description above. The problematic use case is as follows:

  • A user is not logged in and tries and access a protected resource such as: localhost:8080/bignibou/curriculum/#/view/1 (by pasting this url in browser's address bar for instance).
  • They will automatically be redirected to the following Url: http://localhost:8080/bignibou/signin#/view/1

Notice the part including and after the hash sign is kept. Note that this has more to do with AngularJs than Spring Security as Spring Security does not include the hash sign (this is confirmed by the fact that the hash never appears in the network tab of chrome dev tools...)

balteo
  • 23,602
  • 63
  • 219
  • 412
  • 1
    I don't think it is Spring Security doing this since the # portion of a URL is not submitted to the Server. Please check (using something like Chrome Dev tools) to see if the server response includes the # portion or not. – Rob Winch Feb 13 '14 at 17:23
  • @All: I am surprised other people have not met this issue before me and there does not exist a portable solution using AngularJs api... – balteo Feb 18 '14 at 14:39

2 Answers2

4

Rather than Angular, this sounds like the intended behavior for hash fragments on HTTP/3xx redirects, as implemented by most modern browsers (and IE9 onwards, I believe). There is a detailed explanation on the nuances here:

URL Fragments and Redirects

and the official documentation is here:

W3C URI handling - Section 4.1.

Edit:

In order to modify (or, in this case, remove) the fragment, you can leverage HTML5's history state. Try adding this to your signin page:

history.replaceState("", document.title, window.location.pathname + window.location.search)

For further information on the replaceState, it's pretty well documented at Adding and modifying history entries in the Mozilla developer docs.

The obvious caveat here, is what versions of IE you need it to work in. From a quick google, it seems like you are looking at IE10 onwards, so for earlier versions, you would therefore need something more rudimentary like:

window.location.hash = ""

which will remove the fragment but retain the #, but hey, it's IE.

As a composite solution, therefore, you could use:

if("replaceState" in history)
  //  proper browsers
  history.replaceState("", document.title, window.location.pathname + window.location.search)
else
  // fallback for ie
  window.location.hash = ""
scarlz
  • 2,512
  • 1
  • 17
  • 20
  • Thanks. I read the link: it is very interesting. You are right: the culprit here is Chrome and not AngularJs. Do you have any idea how I could remove the "hash part"? – balteo Feb 16 '14 at 08:26
  • I've edited my post with how you can manipulate the hash via javascript. – scarlz Feb 16 '14 at 13:56
  • Is this a solution that is really portable on all browsers? – balteo Feb 18 '14 at 14:38
  • 1
    It will be, yes. For peace of mind, I've googled around, and a very similar answer is proposed here: http://stackoverflow.com/questions/1397329/how-to-remove-the-hash-from-window-location-with-javascript-without-page-refresh#5298684. – scarlz Feb 18 '14 at 15:33
  • What is the best practice in order to put this in place? Should I then have this function (`history.pushState`) invoked automatically when a user lands on `/signin`? – balteo Feb 18 '14 at 15:45
  • Pretty much, yes. I'd likely place it in a function and call it in `` on any pages that require the fragment to be removed. Note that using `.replaceState` is preferable to `.pushState` - the latter adds an extra history entry, meaning going back from `/signin` would take you to `/signin#!/bar` instead of the actual previous page. – scarlz Feb 18 '14 at 17:17
2

As Rob mentioned above, the hash is not being sent back by the server, it is simply being preserved by the browser.

You could however set your login and session expired URLs to `/login#' so that the server returns a hash in the redirect URL, thereby overriding any existing hash.

manish
  • 19,695
  • 5
  • 67
  • 91