Maintain user's session (HttpSession) after login in Spring Boot application

Viewed 1817

I'm creating a simple hotel reservation web application in Spring. Currently, I'm building the actual implementation of booking functionality, employing HttpSession to store data between requests to the server.

Please find the reservation flow below:

Step 1: url: "/" (index page) - user selects location, check-in and check-out dates

Step 2: url: "/reservation/roomselection" - user chooses one out of three room types available

Step 3: url: "/auth/guest/reservation/details" - user adds additional information and confirms the reservation

IMPORTANT Before entering Step 3, user needs to get authenticated on the login page (url: "/login"), so therefore he is automatically redirected to the login page and after successful authentication is redirected to Step's 3 url.

The whole session worked fine (app remembered all information until the third step), until I introduced authentication before step 3. After login all information is being lost and the JSESSIONID cookie is recreated (the previous one is being lost).

I do understand the cause of that issue - my login mapping is in different controller and I'd like to keep it there.

I'd like to ask whether there is any simple solution that I could keep the same SESSIONID and all information until step 3 (after login page)?

My desires are as follows:

  • would like to avoid moving login mapping from HomeController to the ReservationController
  • would like to keep the authentication between step 2 and step 3.

I attach the code of my ReservationController, ReservationDto as well as HomeController (with login page).

Thank you for all the answers!

@Controller
@RequestMapping("/")
@SessionAttributes("reservationDto")
public class ReservationController {

    private Logger LOG = LoggerFactory.getLogger(getClass());

    private final HotelService hotelService;

    public ReservationController(HotelService hotelService) {
        this.hotelService = hotelService;
    }

    @GetMapping
    public String home(Model model) {
        model.addAttribute("hotelsNames", hotelService.findAllHotelsNames());
        model.addAttribute("reservationDto", new ReservationDto());
        return "index";
    }

    @PostMapping("reservation/roomselection")
    public String getRoomSelectionPage(@ModelAttribute("reservationDto") ReservationDto reservationDto,
                                       HttpSession session,
                                       Model model) {
        ReservationDto reservation = (ReservationDto) session.getAttribute("reservationDto");
        LOG.info("Hotel Name form the session: {} and session id {} and creation time: {}, checkin {} ", reservation.getHotelName(), session.getId(), session.getCreationTime(), reservation.getCheckInDate());
        model.addAttribute("reservationDto", reservation);
        return "reservation/roomselection";
    }

    @GetMapping("auth/guest/reservation/details")
    public String getReservationDetailsPage(@ModelAttribute("reservationDto") ReservationDto reservationDto,
                                            HttpSession session,
                                            HttpServletRequest request,
                                            Principal principal,
                                            Model model) {
        String param = request.getParameter("roomType");
        ReservationDto reservation = (ReservationDto) session.getAttribute("reservationDto");
        reservation.setRoomTypeName(param);
        model.addAttribute("reservationDto", reservation);
        LOG.info("Hotel Name form the session: {}, roomType {} and session id {} and creation time: {}, checkin {} and username {}", reservation.getHotelName(), reservation.getRoomTypeName(), session.getId(), session.getCreationTime(), reservation.getCheckInDate(), principal.getName());
        return "reservation/details";
    }

    @GetMapping("/auth/guest/reservation/summary")
    public String getReservationSummary() {
        return "reservation/summary";
    }

}
@Component
@Scope(value = WebApplicationContext.SCOPE_SESSION,
 proxyMode = ScopedProxyMode.TARGET_CLASS)
public class ReservationDto {

    private String username;

    private String reservationNumber;
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private LocalDate checkInDate;
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private LocalDate checkOutDate;

    private String secondGuestName;

    private String thirdGuestName;

    private String fourthGuestName;

    private String message;

    private String hotelName;

    private String roomTypeName;

}
@Controller
public class HomeController {

    private Logger LOG = LoggerFactory.getLogger(getClass());

    private final HotelService hotelService;

    public HomeController(HotelService hotelService) {
        this.hotelService = hotelService;
    }

    @GetMapping("/login")
    public String login() {

        return "login";
    }

}

UPDATE - added Security Config

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {


    private final DataSource dataSource;

    public SecurityConfiguration(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.jdbcAuthentication()
                .dataSource(dataSource)
                .passwordEncoder(passwordEncoder())
                .usersByUsernameQuery("SELECT username, password, active FROM users WHERE username = ?")
                .authoritiesByUsernameQuery("SELECT u.username, r.name FROM users u JOIN roles r ON r.id = u.role_id WHERE u.username = ?");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
                .antMatchers("/").permitAll()
                .antMatchers("/hello").permitAll()
                .antMatchers("/register/**").permitAll()
                .antMatchers("/login").permitAll()
                .antMatchers("/auth/guest", "/auth/guest/**").hasRole("GUEST")
                .antMatchers("/auth/admin", "/auth/admin/**").permitAll() // it will be hasRole("ADMIN")
                .antMatchers("/auth/reception", "/auth/reception/**").permitAll() // it will be hasRole("Receptionist")
                .anyRequest().permitAll()
                .and()
            .formLogin()
                .loginPage("/login")
                .usernameParameter("username")
                .passwordParameter("password")
                .defaultSuccessUrl("/")
                .and()
            .logout()
                .logoutSuccessUrl("/");

    }


    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring()
                .antMatchers("/static/**")
                .antMatchers("/h2-console", "/h2-console/**");
    }
    
}
0 Answers
Related