调用不存在的端点时收到 403 而不是 404

2023-11-23

这是 Spring Security 配置的典型部分:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.csrf().and().cors().disable();
    http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    http.authorizeRequests().antMatchers("/login", "/api/v1/auth/**").permitAll();
    http.authorizeRequests().anyRequest().authenticated();
}

我有一个问题http.authorizeRequests().anyRequest().authenticated().

添加后,当我调用不存在的端点时,例如:获取:/api/v1/不存在, 我收到403而不是预期的404回复。

我想保护我的所有资源,但我想在调用不存在的资源时得到 404。

我该如何修复它?


我对这种行为很满意。如果用户没有经过身份验证,为什么还要费心告诉他有关您系统的更多信息。就像如果一个用户没有权限查看你的硬盘,为什么需要让他可以发现你的硬盘目录树结构。

如果确实想返回 404 ,则需要自定义AuthenticationEntryPoint and AccessDeniedHandler in the ExceptionTranslationFilter。如果用户没有足够的权限来访问端点(即,AccessDeniedException发生)。前者针对匿名用户,后者针对非匿名用户(即认证成功但没有足够权限的用户)

它们的默认实现(即Http403ForbiddenEntryPoint and AccessDeniedHandlerImpl)现在只需返回 403 即可。您必须自定义它们,以便它们首先检查是否存在现有端点来服务当前的HttpServletRequest如果没有则返回404。您可以通过循环来完成HandlerMapping在 - 的里面DispatcherServlet并检查是否有任何HandlerMapping可以处理当前的HttpServletRequest.

首先创建一个执行此检查的对象:

public class HttpRequestEndpointChecker {

    private DispatcherServlet servlet;

    public HttpRequestEndpointChecker(DispatcherServlet servlet) {
        this.servlet = servlet;
    }

    public boolean isEndpointExist(HttpServletRequest request) {

        for (HandlerMapping handlerMapping : servlet.getHandlerMappings()) {
            try {
                HandlerExecutionChain foundHandler = handlerMapping.getHandler(request);
                if (foundHandler != null) {
                    return true;
                }
            } catch (Exception e) {
                return false;
            }
        }
        return false;
    }
}   

然后定制AuthenticationEntryPoint and AccessDeniedHandler使用此对象进行检查:

public  class MyAccessDeniedHandler extends AccessDeniedHandlerImpl {
    private HttpRequestEndpointChecker endpointChecker;

    public MyAccessDeniedHandler(HttpRequestEndpointChecker endpointChecker) {
        this.endpointChecker = endpointChecker;
    }

    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response,
            AccessDeniedException accessDeniedException) throws IOException, ServletException {

        if (!endpointChecker.isEndpointExist(request)) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND, "Resource not found");
        } else {
            super.handle(request, response, accessDeniedException);
        }
    }
}
public class MyAuthenticationEntryPoint extends Http403ForbiddenEntryPoint {

        private HttpRequestEndpointChecker endpointChecker;

        public MyAuthenticationEntryPoint(HttpRequestEndpointChecker endpointChecker) {
            this.endpointChecker = endpointChecker;
        }

        @Override
        public void commence(HttpServletRequest request, HttpServletResponse response,
                AuthenticationException authException) throws IOException {
            if (!endpointChecker.isEndpointExist(request)) {
                response.sendError(HttpServletResponse.SC_NOT_FOUND, "Resource not found");
            } else {
                super.commence(request, response, authException);
            }
        }
}

并配置它们:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private DispatcherServlet dispatcherServlet;

    @Autowired
    private HttpRequestEndpointChecker endpointChecker;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
            ..............
            ..............
            http.exceptionHandling()
                .authenticationEntryPoint(new MyAuthenticationEntryPoint(endpointChecker))
                .accessDeniedHandler(new MyAccessDeniedHandler(endpointChecker));

    }

    @Bean
    public HttpRequestEndpointChecker endpointChecker() {
        return new HttpRequestEndpointChecker(dispatcherServlet);
    }

}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

调用不存在的端点时收到 403 而不是 404 的相关文章

随机推荐