You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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中,步骤如下:

  1. 在LoginView中注入SessionRegistry:
@Autowired
private SessionRegistry sessionRegistry;
  1. 修改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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 15:35:53