Spring Boot应用程序登录后维护用户会话(HttpSession)

mac*_*ejd 6 java spring spring-mvc spring-security spring-session

我正在 Spring 创建一个简单的酒店预订 Web 应用程序。目前,我正在构建预订功能的实际实现,使用 HttpSession 来存储对服务器的请求之间的数据。

请参阅以下预订流程:

第 1 步:url:“/”(索引页)- 用户选择位置、入住和退房日期

第 2 步:url:“/reservation/roomselection” - 用户从三种可用房间类型中选择一种

第 3 步:url:“/auth/guest/reservation/details” - 用户添加附加信息并确认预订

重要提示 在进入步骤 3 之前,用户需要在登录页面(url:“/login”)上进行身份验证,因此他会自动重定向到登录页面,并且在身份验证成功后重定向到步骤 3 的 url。

整个会话工作正常(应用程序记住了所有信息,直到第三步),直到我在步骤 3 之前引入了身份验证。登录后,所有信息都将丢失,并且 JSESSIONID cookie 将被重新创建(前一个信息将丢失)。

我确实了解该问题的原因 - 我的登录映射位于不同的控制器中,我想将其保留在那里。

我想问是否有任何简单的解决方案可以让我保留相同的SESSIONID和所有信息直到步骤3(登录页面之后)?

我的愿望如下:

  • 希望避免将登录映射从 HomeController 移动到 ReservationController
  • 希望在步骤 2 和步骤 3 之间保留身份验证。

我附上了 ReservationController、ReservationDto 以及 HomeController(带有登录页面)的代码。

感谢您的所有回答!

@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";
    }

}
Run Code Online (Sandbox Code Playgroud)
@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;

}
Run Code Online (Sandbox Code Playgroud)
@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";
    }

}
Run Code Online (Sandbox Code Playgroud)

更新 - 添加了安全配置

@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/**");
    }
    
}
Run Code Online (Sandbox Code Playgroud)