我们在控制器上使用带有@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处理程序。
答案 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 而不是来重建执行链。这不是我们想要的,所以我们可以覆盖它以返回输入链。