1

I have a Spring Boot UI application. I am trying to redirect users to the originally requested URL after login.

When a user requests http://www.example.com/myapp/user/22, the application aptly redirects to http://www.example.com/myapp/login. Once the user logs in, the application redirects to http://www.example.com/myapp/dashboard. I would like the application to redirect to http://www.example.com/myapp/user/22.

I have gone through several links and feel I have a proper configuration, yet, redirection is not working as expected.

My Security Config is

public class SecurityConfig extends WebSecurityConfigurerAdapter {
.....
....

    @Autowired
    private MyAuthenticationSuccessHandler authenticationSuccessHandler;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.
        authorizeRequests()
                .antMatchers("/user/**").authenticated()
                .and().csrf().disable().formLogin()
                .successHandler(authenticationSuccessHandler)
......

and My Success Handler is

    @Component
    public class MyAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
    ...
public MyAuthenticationSuccessHandler() {
        super();
        this.setDefaultTargetUrl("/myapp/dashboard");
        this.setUseReferer(true);
    }

        @Override
        public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
                Authentication authentication) throws IOException, ServletException {
            //Do something ..........
            ........
            .........
            super.onAuthenticationSuccess(request, response, authentication);
}

I tried using SavedRequestAwareAuthenticationSuccessHandler too.

I notice that my success handler is invoked, but the target URL is always /user/login and my login controller is invoked..

@RequestMapping("/login")
public ModelAndView login(@ModelAttribute() {
    if(!userIdentified) {
        //go to login page
    } else {
        new ModelAndView("redirect:/myapp/dashboard");
    }
}

and the user is redirected to "dashboard".

What else am I missing?

Jeet
  • 311
  • 1
  • 4
  • 21

3 Answers3

6

Use "Referer" from session attribute to get the latest request URL. On my app, i use this one

public class CustomAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {

    public static final String REDIRECT_URL_SESSION_ATTRIBUTE_NAME = "REDIRECT_URL";

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
            Authentication authentication) throws IOException, ServletException {

        Object redirectURLObject = request.getSession().getAttribute(REDIRECT_URL_SESSION_ATTRIBUTE_NAME);

        if(redirectURLObject != null)
            setDefaultTargetUrl(redirectURLObject.toString());
        else{
            setDefaultTargetUrl("/");
        }

        request.getSession().removeAttribute(REDIRECT_URL_SESSION_ATTRIBUTE_NAME);
        super.onAuthenticationSuccess(request, response, authentication);
    }

}

Edit :

Sorry i forgot to show the login controller

@RequestMapping(method = RequestMethod.GET, value = {"/login"})
    String login(Model model, Principal principal, HttpServletRequest request) throws Exception{
        String referer = request.getHeader("Referer"); //Get previous URL before call '/login'

        //save referer URL to session, for later use on CustomAuthenticationSuccesshandler
        request.getSession().setAttribute(CustomAuthenticationSuccessHandler.REDIRECT_URL_SESSION_ATTRIBUTE_NAME, referer); 


        return principal == null ?  "login" : "redirect:/"; 
    }
  • 1
    Hmmm......the redirect url object is always null. Am I missing some other configuration? How/Where is that attribute set? – Jeet Jun 07 '18 at 13:56
  • Sorry, just updated the answer, let me know if it works – Singgih Suryo P Jun 08 '18 at 04:49
  • The Referer is also null :( Failure URL is triggered... .failureUrl("/myapp/login?error=true") and I'm guessing that's how the /login is called. – Jeet Jun 08 '18 at 14:05
  • Mine works well, maybe its just missing security config. Check out [here](https://stackoverflow.com/questions/14573654/spring-security-redirect-to-previous-page-after-successful-login) and [here](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referer) – Singgih Suryo P Jun 08 '18 at 17:03
  • Argh!!! Figured out the issue. We have an ExceptionResolver with @ExceptionHandler(AccessDeniedException.class) annotated method which redirected to /myapp/login. Hence, I was getting a 302 redirect which set referer to /login. Now, I set the referer in session in this method, and used it in MyAuthenticationSuccessHandler to redirect. I also did this.setUseReferer(false); Everything working as expected now. Thanks Singgih. – Jeet Jun 09 '18 at 16:55
  • For me, the referrer is returning the last browsed page, not the secured page which the user requested. And after login, I am redirected to the last browsed page. Am I missing anything? how I could set the referrer to the requested page? – Rashid May 08 '21 at 18:17
3

Although Singgih S answer works, BUT there is a better way as below : Ref: https://www.baeldung.com/spring-security-redirect-login

There is no magic in these easy to use features in Spring Security. When a secured resource is being requested, the request will be filtered by a chain of various filters. Authentication principals and permissions will be checked. If the request session is not authenticated yet, AuthenticationException will be thrown.

The AuthenticationException will be caught in the ExceptionTranslationFilter, in which an authentication process will be commenced, resulting in a redirection to the login page.

Therefore :
1. When redirection to the "/login" page occurs, your secured request url is saved in the session as DefaultSavedRequest object.
2. Also we know when a successful form based login occurs, one of the implementations of AuthenticationSuccessHandler is called. so we can create a custom class and get DefaultSavedRequest in it as below :

public class CustomAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {


    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        DefaultSavedRequest defaultSavedRequest = (DefaultSavedRequest) request.getSession().getAttribute("SPRING_SECURITY_SAVED_REQUEST");
        if(defaultSavedRequest != null){
            getRedirectStrategy().sendRedirect(request, response, defaultSavedRequest.getRedirectUrl());
        }else{
            super.onAuthenticationSuccess(request, response, authentication);
        }
    }
}


3. We have to introduce this class in WebSecurityConfigurerAdapter :

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.(...).anyRequest().authenticated().and()
                        .formLogin()
                        .loginPage("/login")
                        .loginProcessingUrl("/login")
                        .successHandler(new CustomAuthenticationSuccessHandler());

So you can implement your logic in the above onAuthenticationSuccess method.
Best wishes

Ghasem Sadeghi
  • 1,734
  • 13
  • 24
0

The Spring route, ala extending SavedRequestAwareAuthenticationSuccessHandler or SimpleUrlAuthenticationSuccessHandler can be a bit clunky to implement. In the controller (ex. a POST method that processes logins), you can do the header request yourself; ex:

HttpServletRequest request =null;

String priorUrl = request.getHeader("Referer");

You will notice that you will have the URL prior to either a manual (initiated by user) logout or a session timeout (as handled by Spring session): you'll get an https://iAmPriorUrl.com/.... Then you can do whatever you want with it.

Isaac Riley
  • 290
  • 4
  • 5