如何说服spring 4.2将OPTIONS请求传递给控制器​​

时间:2016-03-14 08:02:09

标签: java spring spring-mvc cors

我们在控制器上使用带有@RestController注释的spring mvc,并且我们正在处理控制器中的授权。我们使用相同的代码来设置响应CORS飞行前请求的允许方法。要做到这一点,我们有:

    <init-param>
        <param-name>dispatchOptionsRequest</param-name>
        <param-value>true</param-value>
    </init-param>

在调度程序servlet的配置中,然后我们有:

    @RequestMapping(value="/some/collections", method=RequestMethod.OPTIONS)
    public void collectionOptions(
            HttpServletRequest req,
            HttpServletResponse res) {
        List<RequestMethod> methods = new ArrayList<>();
        // check actual permissions, add the appropriate methods
        CORS.setAllowedMethodHeaders(res,methods);
    }

我们还有一个拦截器,可以对CORS pre-flight进行基本检查,看看原点是否可能具有任何权限。

我们这样做主要是因为某些请求的权限实际上取决于@RequestParams,即:

    OPTIONS /api/collections?userId=122
如果您拥有管理权限,或者您实际上是ID为122的用户,则可能允许

。此外,我们还有API密钥,所以

    OPTIONS /api/collections?userId=122&apiKey=ABC

可能适用于一个来源,但不适用于另一个来源。

这样可以正常工作,但是现在,第4.2版决定是否处理OPTIONS请求,通过调用:

    CorsUtils.isCorsRequest(request);

在AbstractHandlerMapping中,然后返回

        HandlerInterceptor[] interceptors = chain.getInterceptors();
        chain = new HandlerExecutionChain(new PreFlightHandler(config), interceptors);

而不是HandlerMethod ......

我们需要的是告诉spring让控制器处理OPTIONS请求的一些方法,无论预检请求处理程序是什么。

我们似乎无法找到一个点,我们可以告诉内置的CORS处理是安静的,或者在某处配置一些子类,以便我们绕过新添加的代码: / p>

  AbstractHandlerMapping.getHandler(HSR request)

这有可能吗?在我主动启用它之前(通过WebMvcConfigurerAdapter或通过@CrossOrigin注释),这样的功能是否安静并不会很安​​静?

--------编辑-------------

HTTP标准说明了以下关于OPTIONS方法的内容:

OPTIONS方法表示请求获取有关Request-URI标识的请求/响应链上可用的通信选项的信息。此方法允许客户端确定与资源相关的选项和/或要求,或服务器的功能,而不会暗示资源操作或启动资源检索。

认为beyong只是CORS,我认为拦截一个CORS选项调用虽然相应的方法被映射到控制器上并不是正确的方法。是的,CORS是你可以用OPTIONS调用做的一件事。但它绝不是唯一的一个。

如果没有映射,并且如果使用不同的请求方法和@CrossOrigin注释映射处理程序方法,那么我希望触发内置CORS支持的假设会很好,但我不认为任何具有原始标头集的请求应该只自动转到CORS处理程序。

2 个答案:

答案 0 :(得分:3)

正如zeroflagl所建议的,我也认为混合访问控制和CORS并不是一个好主意。你应该记住,只有预检CORS请求是OPTIONS个。

如果您需要自定义Spring CORS处理,可以使用AbstractHandlerMapping#setCorsProcessor()提供自己的实现,最终可以扩展DefaultCorsProcessor

请注意,默认情况下,CORS处理已启用,但不允许远程源,因此很少需要自定义CorsProcessor。有关this blog post的更多信息。

您的访问控制检查可以作为常规HandlerInterceptor完成,因为成功的CORS预检请求将跟随实际请求。

答案 1 :(得分:2)

我只是说服Spring 4.3通过添加自定义处理程序映射将CORS预检传递给我的控制器:

public class CorsNoopHandlerMapping extends RequestMappingHandlerMapping {

    public CorsNoopHandlerMapping() {
        setOrder(0);  // Make it override the default handler mapping.
    }

    @Override
    protected HandlerExecutionChain getCorsHandlerExecutionChain(HttpServletRequest request,
             HandlerExecutionChain chain, CorsConfiguration config) {
        return chain;  // Return the same chain it uses for everything else.
    }
}

注意:您仍然需要告诉Spring将OPTIONS请求分配给您的控制器 - 也就是说,将dispatchOptionsRequest设置为dispatcherServlet中的true,就像它在this question中所说的那样

为什么工作

Sébastien的above answer建议您使用自己的CorsProcessor。据我所知,这仍然不会使用您的控制器作为处理程序;它只会将不同的CorsProcessor传递给自己的CORS处理程序。

默认情况下,方法AbstractHandlerMapping#getCorsHandlerExecutionChain在检测到预检时会抛出控制器。它不是使用您的控制器作为处理程序,而是实例化一个新的PreFlightHandler并使用它。见Spring source code。这是有问题的一行:

chain = new HandlerExecutionChain(new PreFlightHandler(config), interceptors);

它在这里做的是使用PreFlightHandler 而不是来重建执行链。这不是我们想要的,所以我们可以覆盖它以返回输入链。