如果一个用户没有通过身份验证,为什么还要担心向他提供更多关于您系统的信息呢?我认同这种行为。就像如果一个用户没有权限���看您的硬盘,为什么还要让他发现您的硬盘目录树结构一样。
如果您真的想返回404状态码,您需要自定义 ExceptionTranslationFilter
中的 AuthenticationEntryPoint
和 AccessDeniedHandler
。当用户没有足够的权限访问端点时(即AccessDeniedException
发生) ,它们两个都会被调用。前者是针对匿名用户的,后者是针对已成功身份验证但权限不足的非匿名用户。
它们两个的默认实现(即 Http403ForbiddenEntryPoint
和 AccessDeniedHandlerImpl
)现在只会返回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;
}
}
然后定制 AuthenticationEntryPoint
和 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);
}
}