简体   繁体   中英

Redirect to desired location after login

I know this question can be found with different solutions. But I am unable to get it working in my project.

We are sending mails to users which has link to perform some action in the application. When user click on url he should be redirect to login page if he is not logged in and after login should be navigated to the targeted URL.

I am trying to fix using CustomLoginSuccessHandler here is the code.:

public class CustomLoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
//    public CustomLoginSuccessHandler(String defaultTargetUrl) {
//        setDefaultTargetUrl(defaultTargetUrl);
//    }

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws ServletException, IOException {
        HttpSession session = request.getSession(false);
        if (session != null) {
            String redirectUrl = (String) session.getAttribute("url_prior_login");
            if (redirectUrl != null) {
                // we do not forget to clean this attribute from session
                session.removeAttribute("url_prior_login");
                // then we redirect
                getRedirectStrategy().sendRedirect(request, response, redirectUrl);
            } else {
                super.onAuthenticationSuccess(request, response, authentication);
            }
        } else {
            super.onAuthenticationSuccess(request, response, authentication);
        }
    }
}

Configurations I am using are:

    @Bean
    public SavedRequestAwareAuthenticationSuccessHandler authenticationSuccessHandler(){
        CustomLoginSuccessHandler successHandler = new CustomLoginSuccessHandler();
//        SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
//        successHandler.setUseReferer(true);    getting NULL in the controller every time
//        successHandler.setTargetUrlParameter("targetUrl"); this also doesnt work as browser is redirect to /login page and URL parameters are lost
        return successHandler;
    }

protected void configure(HttpSecurity http) throws Exception {
        http
                .logout().logoutUrl("/logout").deleteCookies("JSESSIONID").logoutSuccessUrl("/logoutSuccess")
                .and()
                .authorizeRequests()
                .antMatchers("/privacyPolicy", "/faq", "/aboutus", "/termsofuse", "/feedback","/feedbackSubmit", "/contactSsm", "/resources/**", "/userReply", "/userReplySubmit", "/image", "/logoutExternal", "/closeit").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .successHandler(authenticationSuccessHandler)
                .loginPage("/login")
                .defaultSuccessUrl("/")
                .permitAll();
//            .and().exceptionHandling().authenticationEntryPoint(new CustomAuthenticationEntryPoint());
    }

Problem using this configuration is, If i request for url say 'http:localhost:8080/showPage' spring security is navigating to 'http:localhost:8080/login' and I am unable to capture anything from original URL. Same problem occurs when I try to use a custom variable targetUrl and using it in the same CustomLoginSuccessHandler.

Please let me know if am taking a wrong approach or something else is missing

Also tried using Custom EntryPoint but unable to redirect using my entrypoint.

@Component
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint{

    private final RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        request.getSession().setAttribute("targetUrl",request.getRequestURL());
        redirectStrategy.sendRedirect(request,response,request.getRequestURL().toString());
    }
}

Controller:

@RequestMapping(value="/login")
public ModelAndView loginHandler(HttpServletRequest request) {
    ModelAndView mav = new ModelAndView();

    String targetUrl = request.getParameter("targetUrl");
    if(targetUrl!=null){ // targetUrl is always null as spring security is navigating to /login asd parameters are lost
        request.getSession().setAttribute("url_prior_login",targetUrl);
    }
    mav.setViewName("login");
    return mav;
}

To login, page is navigated to a different domain. and I pass a redirect URL to that domain after successful login it redirects the page back to the redirecturl

<a href="https://domain/sso/identity/login?channel=abc&ru=${externalUrl.applicationUrl}login" >Sign In</a>

Spring Security already stores the request using a RequestCache the default implementation HttpSessionRequestCache stores the last request in the HTTP session. You can access it using the SPRING_SECURITY_SAVED_REQUEST attribute name to get it from the session.

Doing something like this in your controller

public ModelAndView login(HttpServletRequest req, HttpSession session) {
    ModelAndView mav = new ModelAndView("login");
    if (session != null) {
        SavedRequest savedRequest = session.getAttribute("SPRING_SECURITY_SAVED_REQUEST");
        if (savedRequest != null) {
            mav.addObject("redirectUrl", savedRequest.getRedirectUrl());
        }
    }
    return mav;
}

Then in your JSP you can use the redirectUrl to dynamically construct your URL.

http://your.sso/login?url=${redirectUrl}

The final thing you need to do is to make /login accessible for everyone by adding it to the list which is protected by permitAll() . If you don't do this, you will get into a loop or the last request is overwritten and will always point to the login page.

.antMatchers("/privacyPolicy", "/faq", "/aboutus", "/termsofuse", "/feedback","/feedbackSubmit", "/contactSsm", "/resources/**", "/userReply", "/userReplySubmit", "/image", "/logoutExternal", "/closeit", "/login").permitAll()

You don't need any other custom classes like EntryPoint s or AuthenticationSuccessHandler implementations.

However as you are using SSO it would be probably best to investigate a proper integration with the SSO solution instead of this hack with a login page.

You will at least have one problem : HttpSession session = request.getSession(); .

getSession() Returns the current session associated with this request, or if the request does not have a session, creates one .

You should use getSession(false) if you want a null return in case there is no session.

In your case you'll never get a null session.

I had the same issue and have solved it by using SavedRequestAwareAuthenticationSuccessHandler as a successHandler to make Spring handle the saved request that was requested before redirecting to login page when user is not logged.

In WebSecurityConfigurerAdapter:

import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    private static final String LOGIN_PATH = "/login";

    @Autowired
    MyApplicationAuthenticationSuccessHandler myApplicationAuthenticationSuccessHandler;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // Set the default URL when user enters a non internal URL (Like https://my-application.com)
        myApplicationAuthenticationSuccessHandler.setDefaultTargetUrl("/myapp/home");

        http.authorizeRequests().antMatchers("/resources/**").permitAll().antMatchers(LOGIN_PATH).permitAll().antMatchers("/auto/**").authenticated()
                .and().formLogin().loginPage(LOGIN_PATH).permitAll()
                .successHandler(myApplicationAuthenticationSuccessHandler).and().logout()
                .logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl(LOGIN_PATH)
                .invalidateHttpSession(true).deleteCookies("JSESSIONID").permitAll().and().sessionManagement().invalidSessionUrl(LOGIN_PATH);
    }
}

In custom SavedRequestAwareAuthenticationSuccessHandler:

import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

@Component("myApplicationAuthenticationSuccessHandler")
public class MyApplicationAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
   
    private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request,
      HttpServletResponse response, Authentication authentication)
      throws IOException {
        try {
            super.onAuthenticationSuccess(request, response, authentication);
        } catch (ServletException e) {
            // redirect to default page (home in my case) in case of any possible problem (best solution in my case)
            redirectStrategy.sendRedirect(request, response, "/myapp/home");
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM