在 Spring-data-rest 中使用 Access-Control-Request-Method 发出 OPTIONS 请求时出现 NullPointerException
Posted
技术标签:
【中文标题】在 Spring-data-rest 中使用 Access-Control-Request-Method 发出 OPTIONS 请求时出现 NullPointerException【英文标题】:NullPointerException when making an OPTIONS request with Access-Control-Request-Method in Spring-data-rest 【发布时间】:2019-07-06 16:33:41 【问题描述】:发出 OPTIONS 请求时出现以下异常:
java.lang.NullPointerException: null
at org.springframework.data.rest.webmvc.RepositoryRestHandlerMapping.exposeEffectiveLookupPathKey(RepositoryRestHandlerMapping.java:264) ~[spring-data-rest-webmvc-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.springframework.data.rest.webmvc.RepositoryRestHandlerMapping.lookupHandlerMethod(RepositoryRestHandlerMapping.java:165) ~[spring-data-rest-webmvc-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(AbstractHandlerMethodMapping.java:368) ~[spring-webmvc-5.1.3.RELEASE.jar:5.1.3.RELEASE]
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(AbstractHandlerMethodMapping.java:65) ~[spring-webmvc-5.1.3.RELEASE.jar:5.1.3.RELEASE]
at org.springframework.web.servlet.handler.AbstractHandlerMapping.getHandler(AbstractHandlerMapping.java:401) ~[spring-webmvc-5.1.3.RELEASE.jar:5.1.3.RELEASE]
at org.springframework.data.rest.webmvc.support.DelegatingHandlerMapping$HandlerSelectionResult.from(DelegatingHandlerMapping.java:108) ~[spring-data-rest-webmvc-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.springframework.data.rest.webmvc.support.DelegatingHandlerMapping.getHandler(DelegatingHandlerMapping.java:74) ~[spring-data-rest-webmvc-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.getHandler(DispatcherServlet.java:1231) ~[spring-webmvc-5.1.3.RELEASE.jar:5.1.3.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1014) ~[spring-webmvc-5.1.3.RELEASE.jar:5.1.3.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) ~[spring-webmvc-5.1.3.RELEASE.jar:5.1.3.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) ~[spring-webmvc-5.1.3.RELEASE.jar:5.1.3.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doOptions(FrameworkServlet.java:944) ~[spring-webmvc-5.1.3.RELEASE.jar:5.1.3.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:669) ~[tomcat-embed-core-9.0.13.jar:9.0.13]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882) ~[spring-webmvc-5.1.3.RELEASE.jar:5.1.3.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) ~[tomcat-embed-core-9.0.13.jar:9.0.13]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-9.0.13.jar:9.0.13]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.13.jar:9.0.13]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.13.jar:9.0.13]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.13.jar:9.0.13]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.13.jar:9.0.13]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:320) ~[spring-security-web-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:119) ~[spring-security-web-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137) ~[spring-security-web-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111) ~[spring-security-web-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:170) ~[spring-security-web-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) ~[spring-security-web-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.security.web.authentication.logout.LogoutFilter.
我提出的要求是:
curl 'http://localhost:9091/api/authors' -X OPTIONS -H 'Access-Control-Request-Method: GET' -H 'Origin: http://localhost:3000'
我这样做是为了模仿我最初注意到问题的前端的飞行前请求。
如果我从请求中删除“Access-Control-Request-Method”标头,一切都会正常进行。
我使用的是 SpringBoot 2.1.1 版。这是我的依赖项:
dependencies
implementation('org.springframework.boot:spring-boot-starter-security')
implementation('org.springframework.boot:spring-boot-starter-data-jpa')
implementation('org.springframework.boot:spring-boot-starter-web')
runtimeOnly('com.h2database:h2')
testImplementation('org.springframework.boot:spring-boot-starter-test')
compile 'org.springframework.boot:spring-boot-starter-data-rest:2.0.3.RELEASE'
这是我的安全配置:
@Configuration
@EnableWebSecurity(debug=true)
public class SecurityConfig extends WebSecurityConfigurerAdapter
@Override
protected void configure(HttpSecurity http) throws Exception
你可以在这里找到一个演示项目:https://github.com/cekali/spring-problem
我真的很感谢任何人可以提供的任何帮助,我很难过
【问题讨论】:
【参考方案1】:这是RepositoryRestHandlerMapping
的exposeEffectiveLookupPathKey
方法中的错误。虽然已经在 Github 上修复了,但遗憾的是最新版本(3.1.4.RELEASE)一直没有。
更多信息:
抛出异常是因为该方法需要一个 RequestMappingInfo
对象,该对象封装了来自 HandlerMethod
上的 @RequestMapping
注释的信息。但是对于预检请求,返回并随后使用的HandlerMethod
(参见AbstractHandlerMethodMapping
)没有这样的注释,因此RequestMappingInfo
对象是null
。调用它的方法当然会抛出一个NullPointerException
。
这是您将在 Github 上看到的修复:
private void exposeEffectiveLookupPathKey(HandlerMethod method, HttpServletRequest request, String repositoryBasePath)
RequestMappingInfo mappingInfo = getMappingForMethod(method.getMethod(), method.getBeanType());
if (mappingInfo == null)
return;
...
更新 这已在 3.1.5.RELEASE 中修复
【讨论】:
有什么想法可以在我的应用程序中解决这个问题吗?我目前的解决方案是将 spring-boot 降级为 2.0.5.RELEASE【参考方案2】:您可以按如下方式自定义预检请求:
我有用户 Spring Boot 2.1.3.RELEASE
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter
@Override
protected void configure(HttpSecurity http) throws Exception
http.csrf().disable();
http.cors().and()
.authorizeRequests()
.antMatchers("/**",).permitAll() //custom logic
...................
.............
//define the Corsbean and add your cutom headers here
@Bean
CorsConfigurationSource corsConfigurationSource()
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowCredentials(true);
configuration.setAllowedHeaders(Arrays.asList("Access-Control-Allow-Headers","Access-Control-Allow-Origin",
"Access-Control-Request-Method", "Access-Control-Request-Headers","Origin","Cache-Control",
"Content-Type", "Authorization"));
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("*"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
【讨论】:
以上是关于在 Spring-data-rest 中使用 Access-Control-Request-Method 发出 OPTIONS 请求时出现 NullPointerException的主要内容,如果未能解决你的问题,请参考以下文章
处理事务中的 spring-data-rest 应用程序事件
如何在 Spring-Data-Rest 中实现细粒度的访问控制?