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

如何将REST API从Vaadin错误处理中排除并实现独立认证

问题解决指南

核心问题分析

你需要让REST API的安全机制与Vaadin完全隔离,但当前配置存在以下问题:

  • 多安全链配置错误,导致所有请求(包括Vaadin页面)都进入REST的JWT过滤器
  • Vaadin的安全规则未正确排除API路径,引发未认证请求被重定向到登录页
  • REST登录接口被Vaadin路由拦截,返回HTML而非预期的认证响应

修复步骤

1. 修正多安全链配置(MultiSecurityConfig)

原RestApiSecurityConfig中存在冗余的全局放行规则,导致所有请求都匹配这个过滤器链。需要修改为仅匹配/api路径,并清理无效配置:

@Configuration
@EnableWebSecurity
public class MultiSecurityConfig {

    @Configuration
    @Order(1)
    @RequiredArgsConstructor
    public static class RestApiSecurityConfig {
        private final JwtAuthenticationFilter _jwtAuthenticationFilter;
        private final AuthenticationProvider _authenticationProvider;
        private final RestAuthenticationEntryPoint _restAuthenticationEntryPoint;

        @Bean
        public SecurityFilterChain restApiFilterChain(HttpSecurity http) throws Exception {
            return http
                    // 限定此安全链仅处理/api路径的请求
                    .requestMatcher("/api/**")
                    .csrf(AbstractHttpConfigurer::disable)
                    .authorizeHttpRequests(auth -> auth
                            .requestMatchers("/api/v1/login").permitAll()
                            .anyRequest().authenticated())
                    // 配置REST专属认证入口点,返回401而非重定向
                    .exceptionHandling(ex -> ex.authenticationEntryPoint(_restAuthenticationEntryPoint))
                    .sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                    .authenticationProvider(_authenticationProvider)
                    .addFilterBefore(_jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
                    .build();
        }
    }

    @Configuration
    @Order(2)
    @RequiredArgsConstructor
    public static class VaadinSecurityConfig extends VaadinWebSecurity {
        private final AuthenticationProvider authenticationProvider;

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            // 让Vaadin安全链直接放行/api路径,避免拦截后重定向
            http.authorizeHttpRequests(auth -> auth.requestMatchers("/api/**").permitAll());
            super.configure(http);
            setLoginView(http, LoginView.class);
        }
    }
}

关键修改点:

  • 添加.requestMatcher("/api/**"),确保此安全链只处理API请求
  • 移除冗余的.authorizeHttpRequests().requestMatchers("/**").permitAll()规则
  • 在Vaadin安全链中显式放行/api路径,阻止Vaadin对API请求进行重定向处理

2. 让REST接口跳过Vaadin路由拦截

Vaadin会默认拦截所有未排除的路径,需要在配置中排除API路径,让Servlet容器直接处理:

@Configuration
public class VaadinConfig implements VaadinServletConfiguration {

    @Override
    public void customizeServletRegistration(ServletRegistration.Dynamic registration) {
        // 排除API路径,不经过Vaadin路由处理
        registration.addInitParameter(VaadinServlet.SERVLET_PARAMETER_EXTERNAL_RESOURCES, "/api/**");
    }
}

也可以通过application.properties配置:

vaadin.exclude-urls=/api/**

3. 修复JSESSIONID固定问题

由于REST配置设置了STATELESS,需确保不会触发会话创建:

  • 检查JwtAuthenticationFilter中是否存在request.getSession()这类会隐式创建会话的代码,如有则移除
  • 确保REST安全链的sessionCreationPolicy已设置为STATELESS(步骤1中已配置)

4. 验证RestAuthenticationEntryPoint实现

确保你的认证入口点返回JSON格式的401响应,而非重定向:

@Component
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
        response.setContentType("application/json");
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.getWriter().write("{\"error\":\"Unauthorized\",\"message\":\"Authentication required\"}");
    }
}

测试验证

  1. 不带令牌访问/api端点,应返回401 JSON响应,而非Vaadin登录页
  2. 访问Vaadin页面,应正常跳转到Vaadin登录页
  3. 调用/api/v1/login,应返回JWT令牌,而非HTML页面
  4. 携带有效JWT令牌访问/api端点,应正常返回业务数据

内容的提问来源于stack exchange,提问作者WoistdasNiveau

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 18:45:56