Vaadin24+Spring Security6自定义登录页会话并发管理失效求助
问题:Vaadin 24 + Spring Security 6.3 自定义登录页会话并发管理失效
使用Vaadin 24 + Spring Boot 3 + Spring Security 6.3搭建项目,自定义登录页面后其余功能正常,但会话并发管理始终无法生效。使用Vaadin自带登录组件并设置login.setAction("login")时,会话并发限制功能正常。
我的Security配置
@EnableWebSecurity @Configuration public class SecurityConfiguration extends VaadinWebSecurity { @Bean BCryptPasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean SessionRegistry sessionRegistry() { return new SessionRegistryImpl(); } @Bean public HttpSessionEventPublisher httpSessionEventPublisher() { return new HttpSessionEventPublisher(); } @Bean AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception { return authenticationConfiguration.getAuthenticationManager(); } @Bean SecurityContextRepository securityContextRepository() { return new HttpSessionSecurityContextRepository(); } @Bean public Filter disableOptionsMethodFilter() { return new Filter() { @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; String method = request.getMethod(); if ("OPTIONS".equals(method) || "DELETE".equals(method) || "PATCH".equals(method) || "PUT".equals(method)) { response.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED); } else { chain.doFilter(req, res); } } }; } @Override protected void configure(HttpSecurity http) throws Exception { http.addFilterBefore(disableOptionsMethodFilter(), ChannelProcessingFilter.class) .headers(headers -> headers .xssProtection(xss -> xss.headerValue(XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK)) .frameOptions(frame -> frame.sameOrigin()) .referrerPolicy(referrer -> referrer.policy(ReferrerPolicy.SAME_ORIGIN))) .sessionManagement(session -> session .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) .invalidSessionUrl("/").maximumSessions(1).expiredUrl("/").maxSessionsPreventsLogin(true) .sessionRegistry(sessionRegistry())); setLoginView(http, LoginView.class); super.configure(http); } }
我的登录逻辑
private void doLogin(String username, String password) { if (captcha.checkUserAnswer(captchatext.getValue())) { try { Authentication authentication = new UsernamePasswordAuthenticationToken(username, password); Authentication authenticated = authenticationManager.authenticate(authentication); SecurityContextHolder.getContext().setAuthentication(authenticated); if (authenticated.isAuthenticated()) { SecurityContext context = SecurityContextHolder.getContext(); securityRepo.saveContext(context, VaadinServletRequest.getCurrent(), VaadinServletResponse.getCurrent()); UI.getCurrent().navigate(HomeView.class); } else { Notification.show("Error"); } } catch (Exception e) { Notification.show("Authentication failed"); } } else { Notification.show("Invalid captcha"); } }
问题原因
自定义登录逻辑中,手动认证并保存SecurityContext的方式没有触发Spring Security的会话注册机制。而使用Vaadin自带登录组件并设置login.setAction("login")时,请求会走Spring Security的Filter链,Filter会自动将当前会话与认证用户绑定并注册到SessionRegistry中,从而触发并发会话管理。
解决方案
在手动认证成功后,手动将当前会话注册到SessionRegistry中,步骤如下:
- 在
LoginView中注入SessionRegistry:
@Autowired private SessionRegistry sessionRegistry;
- 修改
doLogin方法,在认证成功后添加会话注册代码:
private void doLogin(String username, String password) { if (captcha.checkUserAnswer(captchatext.getValue())) { try { Authentication authentication = new UsernamePasswordAuthenticationToken(username, password); Authentication authenticated = authenticationManager.authenticate(authentication); SecurityContextHolder.getContext().setAuthentication(authenticated); if (authenticated.isAuthenticated()) { SecurityContext context = SecurityContextHolder.getContext(); securityRepo.saveContext(context, VaadinServletRequest.getCurrent(), VaadinServletResponse.getCurrent()); // 新增:注册当前会话到SessionRegistry HttpSession session = VaadinServletRequest.getCurrent().getSession(); sessionRegistry.registerNewSession(session.getId(), authenticated.getPrincipal()); UI.getCurrent().navigate(HomeView.class); } else { Notification.show("Error"); } } catch (Exception e) { Notification.show("Authentication failed"); } } else { Notification.show("Invalid captcha"); } }
这样就能让Spring Security跟踪当前用户的会话,从而生效并发会话限制规则。
内容的提问来源于stack exchange,提问作者Aiban Marwein
相关产品推荐
相关产品推荐

