Spring Boot应用部署后JWT登录接口返回403问题排查
问题根因
出现本地正常、服务器部署后访问/login返回403的问题,是两个Spring Security配置错误共同导致的:
- 未禁用CSRF防护:Spring Security默认开启CSRF跨站请求伪造防护,仅放行GET/HEAD/OPTIONS这类幂等请求,会对POST/PUT/DELETE等非幂等请求校验CSRF Token,校验失败直接返回403。本地Postman测试可通是因为Postman会自动保存首次访问GET /login时下发的CSRF Cookie,发POST请求时自动携带完成校验;部署到服务器后,Cookie无法正常携带、或请求未提前获取CSRF Token时,就会被CSRF过滤器直接拦截。而你使用的是无状态JWT认证,认证信息不依赖Cookie存储,本身不存在CSRF攻击风险,不需要开启该防护。
- 跨域与权限规则配置不全:你调用的
applyPermitDefaultValues()方法默认仅允许GET/POST/HEAD三种跨域请求方法,未放行跨域预检使用的OPTIONS请求;同时你配置的匿名访问规则仅放行GET方法的/login路径,既没有覆盖登录实际使用的POST方法,也没有给全局OPTIONS请求放行,跨域场景下浏览器发送的预检请求会被认证逻辑直接拦截返回403。
修复方案
按以下步骤调整配置即可解决问题:
- 调整HttpSecurity安全配置,禁用CSRF、补全权限放行规则
修改SecurityConfiguration类的configure(HttpSecurity http)方法,修正后核心配置如下:
@Override protected void configure(HttpSecurity http) throws Exception { http.cors().and().csrf().disable() // 新增禁用CSRF配置 .authorizeRequests() // 放行登录POST请求、所有OPTIONS预检请求 .antMatchers(HttpMethod.POST, SIGN_UP_URL).permitAll() .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() .anyRequest().authenticated() .and() .addFilter(new JWTAuthenticationFilter(authenticationManager())) .addFilter(new JWTAuthorizationFilter(authenticationManager())) .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); // 删除重复的http.logout().permitAll()配置,仅保留一份logout规则 http.logout(logout -> logout .logoutUrl("/logout") .addLogoutHandler(new SecurityContextLogoutHandler()) .permitAll() .clearAuthentication(true)); }
- 修正CORS配置,补全允许的请求方法
修改corsConfigurationSource()方法,调整跨域允许的方法列表:
@Bean CorsConfigurationSource corsConfigurationSource() { final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration corsConfiguration = new CorsConfiguration().applyPermitDefaultValues(); // 补全允许的请求方法,生产环境可按需替换为实际用到的方法 corsConfiguration.addAllowedMethod("*"); source.registerCorsConfiguration("/**", corsConfiguration); return source; }
- 调整测试方式:登录接口必须使用POST方法请求,不要用GET方法携带请求体传用户名密码,GET请求带body不符合HTTP规范,部分反向代理、Web服务器会直接丢弃GET请求的请求体,导致参数解析失败。
内容的提问来源于stack exchange,提问作者KenobiBastila
相关产品推荐
相关产品推荐

