Spring Security配置问题:如何让REST接口同时支持API Key认证和用户登录会话认证
Spring Security配置问题:如何让REST接口同时支持API Key认证和用户登录会话认证
你遇到的核心问题在于REST接口的SecurityFilterChain设置了STATELESS会话策略,这会让Spring Security完全忽略请求中的会话(JSESSIONID),同时该FilterChain里只配置了APIKeyFilter,没有处理会话认证的逻辑。下面给你一步步拆解解决方案:
问题根源分析
你的filterChainREST中设置了sessionCreationPolicy(SessionCreationPolicy.STATELESS),这个配置会告诉Spring Security:
- 不会为REST请求创建新会话
- 完全不读取或使用已有的会话信息
所以即使请求带着已登录用户的JSESSIONID,这个FilterChain也不会去解析会话里的认证数据,直接进入APIKeyFilter的逻辑——如果没有API Key就会走到后续的权限校验,自然会被拒绝。
解决方案步骤
1. 调整REST FilterChain的会话策略
把REST接口的会话策略从STATELESS改为SessionCreationPolicy.IF_REQUIRED(或者直接删掉这行,因为默认就是这个值),让Spring Security允许使用已有的会话:
2. 确保REST FilterChain支持会话认证
去掉STATELESS后,Spring Security会自动添加会话相关的过滤器(比如SessionAuthenticationFilter),这些过滤器会解析请求中的JSESSIONID,加载会话里的用户认证信息。
3. 保留APIKeyFilter的逻辑(无需修改核心逻辑)
你的APIKeyFilter逻辑是对的:当找到有效API Key时设置认证信息,没有找到时直接放行让后续过滤器处理——现在后续过滤器就会处理会话认证了。
修改后的完整代码示例
@Bean @Order(1) public SecurityFilterChain filterChainREST(HttpSecurity http) throws Exception { APIKeyFilter filter = new APIKeyFilter(API_KEYS); http.antMatcher("/api/**") .addFilterBefore(filter, AnonymousAuthenticationFilter.class) .csrf().disable() .authorizeHttpRequests(requests -> requests .antMatchers("/api/1/mgr/**").hasAnyRole("ADMIN", "MGR") .antMatchers("/api/1/admin/**").hasRole("ADMIN") .anyRequest().denyAll()) .sessionManagement() // 替换为IF_REQUIRED,允许使用已有会话 .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED); return http.build(); } @Bean @Order(2) public SecurityFilterChain filterChainWebUI(HttpSecurity http) throws Exception { http .antMatcher("/**") // 处理/api/**之外的所有请求 .csrf().disable() .authorizeHttpRequests() .antMatchers("/admin/**").hasRole("ADMIN") .antMatchers("/mgr/**").hasAnyRole("ADMIN", "MGR") .antMatchers("/login*").permitAll() .anyRequest().authenticated() .and() .formLogin(Customizer.withDefaults()) .logout(l->l.deleteCookies("JSESSIONID")) .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) .and() .exceptionHandling().accessDeniedPage("/error/accessDenied.html"); return http.build(); }
验证效果
修改完成后,访问/api/**接口时会有两种认证路径:
- 带有效API Key:APIKeyFilter会直接设置认证信息,完成权限校验后放行
- 不带API Key但有有效JSESSIONID:Spring Security会自动从会话中加载已登录用户的认证信息,再进行权限校验,符合角色要求就会放行
- 两者都没有:会被权限校验规则拒绝
备注:内容来源于stack exchange,提问作者mwhidden
相关产品推荐
相关产品推荐

