当前位置: 首页 > 知识库问答 >
问题:

为Spring boot中的公共和私有资源使用不同的路径

巫研
2023-03-14

我使用的是Spring boot Jersey Spring security,我想要公共和私有endpoint,我想要一个模式,如下所示:

  • /rest--我的根上下文
  • 我想把我的公共endpoint放在这个上下文中,它必须在根上下文中,比如 /rest/Public/ping 我想把我的私有endpoint放在这个上下文中,它必须在根上下文中,比如 /rest/私有/帐户

我的配置如下:

泽西配置:

@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

谢谢你的帮助:)

共有3个答案

徐凌
2023-03-14

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

如果要允许所有流量通过/Public到达终结点,可以将刚需匹配器添加到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

公良育
2023-03-14

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

以下是一个例子:

@Path("rest")
public class SampleResourceClass {

  @Path("/public/pings")
  @GET
  public Responce getPings(){
    /* Code Here */
  }

  @Path("/private/accounts")
  @GET
  public Response getAccounts(){
    /* Code Here */
  }
}
楚洋
2023-03-14

在servlet容器中,Jersey运行时作为servlet或servlet过滤器运行。spring boot如何配置servlet和过滤器分别是通过ServletRegistrationBeans和FilterRegistrationBeans。要了解该配置在幕后的工作方式,您可以查看JerseyAutoConfiguration

JerseyAutoConfiguration中,您可以看到注入了ResourceConfig,这是用于创建Jersey servlet或Jersey过滤器的ResourceConfig(取决于您选择的配置)。因此,出现错误的原因是您不能有不明确的bean,您有两个ResourceConfigbean。所以Spring不知道该注射哪一种。

不过,您可以为每个ResourceConfig使用两个不同的servlet。问题是SpringBoot只为Jersey连接了一个servlet,所以您需要自己配置另一个servlet。有两种选择:

>

  • 为其中一个泽西应用程序使用Spring Boot自动配置,并为您的另一个应用程序添加另一个ServletAuthstrationBean。需要注意的一件事是,为您创建的ServletAuthstrationBean创建的ResourceConfig不应该是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;
    }
    

    完全不要使用Spring Boot配置。只需创建两个Servlet注册Bean。在这种情况下,您的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应用程序将完全独立,这意味着您需要为这两个应用程序注册提供者(如过滤器)

  •  类似资料:
    • 我有两个终点。 是一个内部(半私有)endpoint。仅允许配置的客户端使用。(不需要用户名和凭据;但clientID就足够了) 问候语是专用endpoint。仅允许客户端和用户配置。(需要clientID、用户名和密码) 以下是配置。 这是控制器 我不能访问没有任何令牌。所以当我尝试使用下面的curl获取访问令牌时(注意我不传递用户名和密码,只传递client_id和client_secret)

    • 但当我通过api Gateway+lambda+NodeJSV8部署我的api时。我已经解决了用于调试的nodejs处理程序函数参数(https://y0gh8upq9d.execute-api.ap-south-1.amazonaws.com/prod)的JSON for event and context varaibles。 lambda函数是 API网关详细信息 使用Lambda代理集成-

    • 如何在Kotlin中创建一个具有私有getter(或只是没有)但具有公共setter的属性? 不能使用错误: 在我的例子中,原因是Java Interop:我希望我的Java代码能够调用,但不能调用。

    • 问题内容: 将方法标记为程序包专用类是否有所不同? 之间和此处的可见性是否有实际差异? 问题答案: 如果该类不会被另一个更可见的子类扩展,则唯一的区别是 intent的清晰度* 。将所有方法包都声明为私有,使以后的读者更加难以确定同一包中的其他类将调用哪些方法。 作为我的设计解决方案,这没有多大意义,但是从技术上来说还是有可能的。

    • 我想为我拥有的一个类编写一个单元测试。这个类有一个公共方法,在公共方法内部有对同一个类中的私有方法的调用。我想模拟对那些私有方法的调用。类与此类似: 对于我的单元测试,我尝试将PowerMock与Mockito和TestNG一起使用。下面是我对测试SomePublicMethod的测试的尝试: 当我运行这个测试时,我会得到一个异常和一些提示: 我在网上看了一些例子,但是我还没有找到一个专门使用Po

    • 我想在共享主机中安装laravel,我遵循了这里的步骤https://stackoverflow.com/a/28449523 但是我的资产路径不包括公共目录 而不是这个 我明白了 如何在不更改任何核心类的情况下更改资产文件夹的目录(将public添加到资产)?