Use different paths for public and private resources Jersey + Spring boot

前端 未结 3 1219
离开以前
离开以前 2020-12-16 16:16

I\'m using Spring boot + Jersey + Spring security, I want to have public and private endpoints, I want an schema as follow:

  • /rest -- My root c
相关标签:
3条回答
  • 2020-12-16 16:50

    You won't be allowed to create two beans for your Resource Class. You can achieve what you are trying to achieve using a single Resource Class as well.

    Here is an example:

    @Path("rest")
    public class SampleResourceClass {
    
      @Path("/public/pings")
      @GET
      public Responce getPings(){
        /* Code Here */
      }
    
      @Path("/private/accounts")
      @GET
      public Response getAccounts(){
        /* Code Here */
      }
    }
    
    0 讨论(0)
  • 2020-12-16 17:08

    In a servlet container, the Jersey runtime, runs as either a servlet or as a servlet filter. How spring boot configures servlets and filters is through ServletRegistrationBeans and FilterRegistrationBeans, respectively. To get an idea of how that configuration works behind scenes, you can look at the source code for the JerseyAutoConfiguration

    In the JerseyAutoConfiguration, you can see that a ResourceConfig is injected, and that is the ResourceConfig used to create the Jersey servlet or Jersey filter (depending on your choice of configuration). So the reason for the error is that you can't have ambiguous beans, which you have two ResourceConfig beans. So Spring doesn't know which one to inject.

    What you can do though, is use two different servlets for each ResourceConfig. The problem is that Spring Boot only hooks you up with one servlet for Jersey, so you need to configure the other one yourself. There are two options:

    1. Use the Spring Boot auto-configuration for one of the Jersey applications, and add another ServletRegistrationBean for your other one. The one thing to note is that the ResourceConfig for your created ServletRegistrationBean should not be a Spring component (i.e. no @Component or @Configuration), or else you will still face the same error.

      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. Don't use the Spring Boot configuration at all. Just create two ServletRegistrationBeans. In this case, none of your ResourceConfig classes should be Spring beans.

      @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;
      }
      

    Personally, I prefer the second option, as it is easier to reason about the configurations when they are all in one place.

    Another thing to note is that the two Jersey applications will be completely independent, meaning you will need to register providers (like filters) for both applications

    0 讨论(0)
  • 2020-12-16 17:13

    The error you are seeing is not related to your security config, you may want to take a look at this ticket, https://github.com/spring-projects/spring-boot/issues/3260

    If you want to permit all traffic to endpoints past /public you can add the RequestMatcher to the Spring Security ignore list.

    @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

    0 讨论(0)
提交回复
热议问题