Spring Security 调用不存在的端点时接收403而不是404

g6baxovj  于 2023-03-08  发布在  Spring
关注(0)|答案(3)|浏览(362)

这是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()有问题。
添加之后,当我调用不存在的端点时,例如:GET:/API/v1/not-existing,我收到了403而不是预期的404响应。
我想保护我所有的资源,但我想得到404时,调用不存在的资源。
我该怎么修呢?

z0qdvdin

z0qdvdin1#

我可以接受这种行为。如果一个用户没有通过身份验证,为什么要费心告诉他更多关于你的系统的信息。就像如果一个用户没有权限查看你的硬盘,为什么要让他可以发现你的硬盘目录树结构。
如果你真的想返回404,您需要在ExceptionTranslationFilter中自定义AuthenticationEntryPointAccessDeniedHandler。如果用户没有足够的权限访问端点,则将调用这两个命令(即AccessDeniedException发生),前者是匿名用户,后者是非匿名用户(即用户成功通过身份验证,但权限不足)
它们的默认实现(即Http403ForbiddenEntryPointAccessDeniedHandlerImpl)现在只返回403。您必须定制它们,使它们首先检查是否有现有端点服务于当前HttpServletRequest,如果没有,则返回404。您可以通过在DispatcherServlet内循环HandlerMapping并检查是否有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;
    }
}

然后自定义AuthenticationEntryPointAccessDeniedHandler以使用此对象进行检查:
x一个一个一个一个x一个一个二个x
并配置它们:

@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);
    }

}
juud5qan

juud5qan2#

在我看来,你唯一的选择是:

@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().antMatchers(all-your-endpoints).authenticated();
    http.authorizeRequests().anyRequest().permitAll();
}

您需要用一个或多个与所有端点匹配的正则表达式替换all-your-endpoints,事实上,您甚至可以去掉http.authorizeRequests().antMatchers("/login", "/api/v1/auth/**").permitAll();,除非您真的想明确表示它。

eblbsuwk

eblbsuwk3#

我也遇到过类似的问题,任何url都是403。过了一段时间,我发现spring从1.5.x更新到更高版本后,声明contextPath的方式发生了变化。所以Spring无法解析我的url,因为我在应用程序.yml上声明了错误
变更自:

server:
  contextPath: /app-name

收件人:

server:  
  servlet:
    contextPath: /app-name

相关问题