公共和私人资源使用不同的路径Jersey + Spring启动

我正在使用Spring boot + Jersey + Spring安全性,我想拥有公共和私有端点,我想要一个架构如下:

  • / rest – 我的根上下文
  • / public – 我想将我的公共端点放在这个上下文中,它必须在/rest/public/pings类的根上下文中
  • / private – 我想将我的私有端点放在这个上下文中,它必须在/rest/private/accounts类的根上下文中

我的配置如下:

泽西配置:

 @Configuration @ApplicationPath("/rest") public class RestConfig extends ResourceConfig { public RestConfig() { register(SampleResource.class); } } 

Spring安全配置:

 @Configuration public class SecurityConfiguration extends WebSecurityConfigurerAdapter { ........ protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().antMatchers("/rest/public/**").permitAll(); http.antMatcher("/rest/**").authorizeRequests().anyRequest().fullyAuthenticated().and().httpBasic(); http.csrf().disable(); } } 

问题是如何在my / rest上下文中注册两个应用程序路径,一个用于/ public,另一个用于/ private?

注意:我尝试创建另一个ResourceConfig,如下所示:

 @Configuration @ApplicationPath("/rest/public") public class RestPublicConfig extends ResourceConfig{ public RestPublicConfig() { register(PingResource.class); } } 

但是我得到了下一个错误:

  No qualifying bean of type [org.glassfish.jersey.server.ResourceConfig] is defined: expected single matching bean but found 2: restConfig,restPublicConfig 

谢谢你的帮助 :)

在servlet容器中,Jersey运行时作为servlet或servletfilter运行。 spring boot如何配置servlet和filter分别是通过ServletRegistrationBeanFilterRegistrationBeans 。 要了解该配置如何在幕后工作,您可以查看JerseyAutoConfiguration的源代码

JerseyAutoConfiguration ,您可以看到注入了ResourceConfig ,这是用于创建Jersey servlet或Jerseyfilter的ResourceConfig (取决于您选择的配置)。 所以错误的原因是你不能有不明确的bean,你有两个ResourceConfig bean。 所以Spring不知道要注入哪一个。

但是你可以做的是为每个ResourceConfig使用两个不同的servlet。 问题是Spring Boot只为你挂了一个针对Jersey的servlet,所以你需要自己配置另一个servlet。 有两种选择:

  1. 对其中一个Jersey应用程序使用Spring Boot自动配置,并为另一个应用程序添加另一个ServletRegistrationBean 。 需要注意的一点是,创建的ServletRegistrationBeanResourceConfig不应该是Spring组件(即没有@Component@Configuration ),否则您仍将面临同样的错误。

     public class PublicConfig extends ResourceConfig { public PublicConfig() { register(PingResource.class); } } ... // in your Spring Boot configuration class @Bean public ServletRegistrationBean publicJersey() { ServletRegistrationBean publicJersey = new ServletRegistrationBean(new ServletContainer(new PublicConfig())); publicJersey.addUrlMappings("/rest/public/*"); publicJersey.setName("PublicJersey"); publicJersey.setLoadOnStartup(0); return publicJersey; } 
  2. 根本不要使用Spring Boot配置。 只需创建两个ServletRegistrationBean 。 在这种情况下,您的ResourceConfig类都不应该是Spring bean。

     @Bean public ServletRegistrationBean publicJersey() { ServletRegistrationBean publicJersey = new ServletRegistrationBean(new ServletContainer(new PublicConfig())); publicJersey.addUrlMappings("/rest/public/*"); publicJersey.setName("PublicJersey"); publicJersey.setLoadOnStartup(0); return publicJersey; } @Bean public ServletRegistrationBean privateJersey() { ServletRegistrationBean privateJersey = new ServletRegistrationBean(new ServletContainer(new PrivateConfig())); privateJersey.addUrlMappings("/rest/private/*"); privateJersey.setName("PrivateJersey"); privateJersey.setLoadOnStartup(1); return privateJersey; } 

就个人而言,我更喜欢第二种选择,因为当它们都在一个地方时,更容易推断配置。

另外需要注意的是,两个Jersey应用程序将完全独立,这意味着您需要为两个应用程序注册提供程序(如filter)

您将不被允许为您的资源类创建两个bean。 您也可以使用单个资源类来实现您想要实现的目标。

这是一个例子:

 @Path("rest") public class SampleResourceClass { @Path("/public/pings") @GET public Responce getPings(){ /* Code Here */ } @Path("/private/accounts") @GET public Response getAccounts(){ /* Code Here */ } } 

您看到的错误与您的安全配置无关,您可能需要查看此票证, https://github.com/spring-projects/spring-boot/issues/3260

如果要允许所有到端点/public端点的流量,可以将RequestMatcher添加到Spring Security忽略列表中。

 @Configuration @EnableWebSecurity public class SecurityConfiguration extends WebSecurityConfigurerAdapter { @Override public void configure(WebSecurity web) throws Exception { web.ignoring().antMatchers("/rest/public/**"); } protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().antMatcher("/rest/private/**") .anyRequest().authenticated().and() .httpBasic().and() .csrf().disable() } } 

http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#jc