为什么Spring Security未按配置返回403,实际返回405响应状态?
问题根因
从日志可以明确问题产生的流程:
- 访问
VERIFY_BADGE_URL时,DelegatingAuthenticationEntryPoint正确匹配到Http403ForbiddenEntryPoint,写入403响应状态 - Spring Boot默认开启错误页自动转发规则,状态码>=400的响应会被服务器转发到
/error路径做统一错误处理,原请求为POST方法,转发后的请求也为POST方法 - 你的项目中
/error路径对应的处理器不支持POST方法,触发HttpRequestMethodNotSupportedException,最终返回405状态码
解决方案
方案1:禁用错误页转发(推荐,符合接口直接返回状态码的需求)
在configure方法的exceptionHandling配置中,补充配置AccessDeniedHandler,同时直接在响应写入状态码后禁止后续转发:
@Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable(); // 你原有的EntryPoint映射配置保持不变 LinkedHashMap<RequestMatcher, AuthenticationEntryPoint> map = new LinkedHashMap<>(); // ... 原有map.put配置不变 http.authorizeRequests() // 原有权限规则不变 .antMatchers(WELCOME_PAGE, FOOD_SELECTION_PAGE + "/**", CHECKOUT_URL, VERIFY_BADGE_URL, VERIFY_NAME_URL).denyAll() .antMatchers(ADMIN_PAGE, NEW_FOOD_PAGE, EDIT_FOOD_URL + "/**", HIDE_FOOD_URL, SHOW_FOOD_URL, DELETE_FOOD_URL, REFRESH_EMPS_URL).hasAnyAuthority("ROLES_USER") .anyRequest().permitAll() .and().formLogin().loginPage(LOGIN_PAGE) .usernameParameter("username") .passwordParameter("pin") .defaultSuccessUrl(ADMIN_PAGE) .permitAll() .failureUrl(LOGIN_PAGE + "?badlogin") .and().exceptionHandling() .authenticationEntryPoint(new DelegatingAuthenticationEntryPoint(map)) // 新增AccessDeniedHandler配置,处理已认证用户权限不足的场景,直接返回403 .accessDeniedHandler((request, response, accessDeniedException) -> { response.setStatus(HttpServletResponse.SC_FORBIDDEN); response.getWriter().flush(); }); }
如果仍有转发问题,可在配置文件application.properties中添加如下配置关闭默认错误页:
server.error.whitelabel.enabled=false
方案2:兼容/error路径POST请求
如果需要保留项目全局错误处理逻辑,直接自定义ErrorController,添加POST方法的支持即可:
@RestController public class CustomErrorController implements ErrorController { @RequestMapping(value = "/error", method = {RequestMethod.GET, RequestMethod.POST}) public ResponseEntity<Map<String, Object>> handleError(HttpServletRequest request) { Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code"); Map<String, Object> error = new HashMap<>(); error.put("code", statusCode); error.put("message", request.getAttribute("javax.servlet.error.message")); return ResponseEntity.status(statusCode).body(error); } }
内容的提问来源于stack exchange,提问作者Brett53559
相关产品推荐
相关产品推荐

