Vaadin 23.3.11中如何实现仅在登录成功后创建会话,而非访问URL时自动创建?
Vaadin 23.3.11中如何实现仅在登录成功后创建会话,而非访问URL时自动创建?
我之前也遇到过一模一样的问题——Vaadin默认一访问应用就会自动创建会话,完全不符合登录后才初始化会话的需求。这其实是因为Vaadin在渲染任何UI视图时,都会自动初始化VaadinSession并绑定到HttpSession,导致会话提前创建。下面我结合你的代码和技术栈,给出两种可行的解决方案:
方法一:调整Vaadin配置+手动控制会话创建
这种方法不需要改动你的Vaadin视图结构,只需要通过配置和代码调整来延迟会话创建:
1. 修改Vaadin会话创建策略
在Spring的application.properties文件中添加配置,告诉Vaadin只有在真正需要的时候才创建HttpSession:
vaadin.servlet.session-creation-mode=if_required
2. 改造LoginView的登录逻辑
默认情况下,哪怕你没主动调用VaadinSession.getCurrent(),Vaadin渲染LoginView时也会自动创建会话。我们需要在登录成功后手动触发会话创建,替换原有的登录按钮逻辑:
Button loginButton = new Button("Login", e -> { logger.info("Inside LoginView.class. Clicked login Button after entering username and password."); String u = username.getValue(); String p = password.getValue(); logger.info("Username is: {}", u); logger.info("Password is: {}", p); if (userRepository.validateUser(u, p)) { logger.info("Valid credentials"); // 手动创建HttpSession(参数true表示不存在则创建) HttpSession httpSession = VaadinServletRequest.getCurrent().getSession(true); // 绑定VaadinSession并设置用户属性 VaadinSession vaadinSession = VaadinSession.getCurrent(); vaadinSession.setAttribute("user", u); String sessionId = httpSession.getId(); logger.info("Session Id is: {}", sessionId); getUI().ifPresent(ui -> ui.navigate("dashboard")); } else { logger.info("Invalid credentials"); Notification.show("Invalid credentials"); } });
3. 保留Dashboard的校验逻辑
你原本在Dashboard里的会话校验逻辑已经没问题了——如果会话不存在(或者用户未登录),就重定向到登录页,直接保留即可:
String user = (String) VaadinSession.getCurrent().getAttribute("user"); if (user == null) { logger.info("Session missing or expired. Redirecting to login."); UI.getCurrent().getPage().setLocation("login"); return; }
方法二:使用纯HTML登录页面(更彻底的方案)
如果方法一还是没办法完全阻止提前创建会话,那么可以把登录页面改成非Vaadin的纯HTML页面,通过Spring MVC控制器处理登录,彻底规避Vaadin的自动会话创建:
1. 创建纯HTML登录页
在src/main/resources/static目录下新建login.html:
<!DOCTYPE html> <html> <head> <title>Login</title> </head> <body> <form action="/login" method="post"> <div> <label>Username: </label> <input type="text" name="username" required> </div> <div> <label>Password: </label> <input type="password" name="password" required> </div> <button type="submit">Login</button> </form> </body> </html>
2. 编写Spring MVC登录控制器
创建一个控制器处理登录请求,验证通过后再重定向到Vaadin的Dashboard:
@Controller public class LoginController { private final UserRepository userRepository; // 构造注入(替代你的手动Bean获取) public LoginController(UserRepository userRepository) { this.userRepository = userRepository; } @GetMapping("/login") public String showLoginPage() { return "login.html"; } @PostMapping("/login") public String processLogin(@RequestParam String username, @RequestParam String password, HttpSession session) { if (userRepository.validateUser(username, password)) { session.setAttribute("user", username); // 重定向到Vaadin的Dashboard视图 return "redirect:/dashboard"; } else { // 登录失败返回登录页 return "redirect:/login?error"; } } }
3. 调整Dashboard的会话读取逻辑
因为现在用户信息存在HttpSession里,需要稍微调整Dashboard的代码:
public Dashboard(){ logger.info("Entered Dashboard View."); // 从HttpSession读取用户信息 String user = (String) VaadinServletRequest.getCurrent().getSession().getAttribute("user"); if (user == null) { logger.info("Session missing or expired. Redirecting to login."); UI.getCurrent().getPage().setLocation("login"); return; } // 剩下的代码保持不变... }
额外优化建议
- Logout逻辑调整:你原来的Logout按钮逻辑可以稍微优化下顺序,确保VaadinSession和HttpSession都被正确销毁:
Button logoutButton = new Button("Logout", e -> { logger.info("Clicked logout button."); // 先关闭VaadinSession VaadinSession.getCurrent().close(); // 再销毁HttpSession VaadinServletRequest.getCurrent().getSession().invalidate(); getUI().ifPresent(ui -> ui.getPage().setLocation("login")); }); - 会话超时设置:你的
SessionConfigListener设置了30秒的超时,这个可以保持,但要注意如果使用方法一,sessionCreated事件只会在登录成功后触发,符合你的预期。
内容来源于stack exchange
相关产品推荐
相关产品推荐

