Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/355.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何告诉spring security仅为特定端口应用授权请求?_Java_Spring_Spring Security_Port - Fatal编程技术网

Java 如何告诉spring security仅为特定端口应用授权请求?

Java 如何告诉spring security仅为特定端口应用授权请求?,java,spring,spring-security,port,Java,Spring,Spring Security,Port,我们将新的微服务(使用Spring Boot)配置为官方API位于端口8080上(在虚拟网络外部映射到端口443上的正常HTTPS),而一些管理功能位于辅助HTTP端口7979上。这些仅用于虚拟网络内部,并用于监视、负载平衡等 所有API访问都需要使用OAuth进行保护,而管理功能应该可以在网络内自由访问。因此,我们以这种方式配置Spring安全性(http是一个HttpSecurity对象): 这对两个端口都有影响:/info和/health未经授权,而/warehouses需要身份验证,其他

我们将新的微服务(使用Spring Boot)配置为官方API位于端口8080上(在虚拟网络外部映射到端口443上的正常HTTPS),而一些管理功能位于辅助HTTP端口7979上。这些仅用于虚拟网络内部,并用于监视、负载平衡等

所有API访问都需要使用OAuth进行保护,而管理功能应该可以在网络内自由访问。因此,我们以这种方式配置Spring安全性(http是一个HttpSecurity对象):

这对两个端口都有影响:
/info
/health
未经授权,而
/warehouses
需要身份验证,其他所有端口也需要身份验证(返回401,但使用身份验证调用时,返回403)

由于公共端口上没有
/info
/health
,因此对于未经授权的用户,这些端口返回404,而其他所有端口返回401。我对此感到不满意,并希望

  • 在公共端口上,要求对所有内容进行身份验证(仅在经过身份验证后返回404或403)
  • 在管理端口上,根本不需要身份验证(对于不是配置的端点之一的所有内容,返回404)
我在SpringSecurityJavadocs或中找不到任何关于端口的信息

我能在这里做什么?

我找到了一个解决方案:

这里的
authorizeRequests()
方法返回一个
ExpressionUrlAuthorizationConfigurer.expressionIntercepturRegistry
,它(从其祖先类AbstractRequestMatcherRegistry)在一些
antMatchers
方法旁边还有一个泛型
requestMatchers()
方法,它接受一个或多个
RequestMatcher
对象。事实证明,这是一个我可以自己实现的接口:

/**
 * A request matcher which matches just a port.
 *
 * @param   port  the port to match.
 *
 * @return  the new matcher.
 */
private RequestMatcher forPort(final int port) {
    return (HttpServletRequest request) -> port == request.getLocalPort();
}
(这是Java8语法,在以前的Java版本中,您必须在这里编写一个anyonymous类。)

虽然
requestMatchers
需要几个这样的匹配器,但看起来它们是通过OR连接的(至少是这样),因此我使用了AndRequestMatcher将其连接到路径(和HTTP方法)的匹配器

最终的代码如下所示:

@Value("${management.port}")
private int managementPort;

@Value("${server.port}")
private int apiPort;

/**
 * Configure scopes for specific controller/httpmethods/roles here.
 */
@Override
public void configure(final HttpSecurity http) throws Exception {
    //J-
    http
        .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER)
        .and()
        .authorizeRequests()
            .requestMatchers(forPortAndPath(managementPort, "/info")).anonymous()
            .requestMatchers(forPortAndPath(managementPort, "/health")).anonymous()

            .requestMatchers(forPortAndPath(apiPort, HttpMethod.GET, "/warehouses/**")).access(oauthScopeRead)
            .requestMatchers(forPortAndPath(apiPort, HttpMethod.PUT, "/warehouses/**")).access(oauthScopeWrite)

            .anyRequest().denyAll();
    //J+
}

/**
 * Creates a request matcher which only matches requests for a specific local port and path (using an
 * {@link AntPathRequestMatcher} for the path part).
 *
 * @param   port         the port to match
 * @param   pathPattern  the pattern for the path.
 *
 * @return  the new request matcher.
 */
private RequestMatcher forPortAndPath(final int port, @Nonnull final String pathPattern) {
    return new AndRequestMatcher(forPort(port), new AntPathRequestMatcher(pathPattern));
}

/**
 * Creates a request matcher which only matches requests for a specific local port, path and request method (using
 * an {@link AntPathRequestMatcher} for the path part).
 *
 * @param   port         the port to match
 * @param   pathPattern  the pattern for the path.
 * @param   method       the HttpMethod to match. Requests for other methods will not be matched.
 *
 * @return  the new request matcher.
 */
private RequestMatcher forPortAndPath(final int port, @Nonnull final HttpMethod method,
        @Nonnull final String pathPattern) {
    return new AndRequestMatcher(forPort(port), new AntPathRequestMatcher(pathPattern, method.name()));
}

/**
 * A request matcher which matches just a port.
 *
 * @param   port  the port to match.
 *
 * @return  the new matcher.
 */
private RequestMatcher forPort(final int port) {
    return (HttpServletRequest request) -> { return port == request.getLocalPort(); };
}
这并没有完全反映出这个问题:managementPort在这里只有可访问的“/info”和“/health”,而不是所有内容

你可以用这个


使此端口完全未经授权。

允许对管理终结点进行所有访问的简单方法,无论它们在哪个端口上运行:

http.authorizeRequests()
.requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll();
该方法返回一个仅匹配执行器请求的匹配器


请参阅以获取更完整的示例。

基于上一个答案,我开发了一个将管理端口排除在安全性之外的类。我希望这有助于:

@EnableWebSecurity
@Configuration
public class WebSecurityAdapter extends WebSecurityConfigurerAdapter {
  /**
   * Puerto de administración por donde escucha Actuator.
   */
  @Value("${management.server.port}")
  private int managementPort;
  /*
   * (non-Javadoc)
   * 
   * @see org.springframework.security.config.annotation.web.configuration.
   * WebSecurityConfigurerAdapter#configure(org.springframework.security.config.
   * annotation.web.builders.WebSecurity)
   */
  @Override
  public void configure(WebSecurity web) throws Exception {
    web.ignoring().requestMatchers(forPort(managementPort));
  }
  /**
   * @param port
   *          Puerto que se desea comparar con el puerto de la respuesta http.
   * @return Verdadero si el puerto de la respuesta http es igual al puerto
   *         especificado.
   */
  private RequestMatcher forPort(int port) {
    return (HttpServletRequest request) -> {
      return port == request.getLocalPort();
    };
  }
}

我仍在寻找解决方案+1是的,我有点作弊。我正在打问题,然后(在提交之前)对答案有了想法,并在决定提交问题之前进行了尝试。然后,我只需根据我已有的代码键入答案。好的解决方案是,没有找到一个好的方法来测试运行在动态端口上的服务器。我在测试类中使用了
@SpringBootTest(webEnvironment=SpringBootTest.webEnvironment.DEFINED_PORT)
,否则
private int-apiPort
将保持为零,我的所有接口都将被禁止使用403。感谢您的回答,但我们不希望所有端点都使用“allow all”,由于这违背了在所有位置进行授权的目的。EndpointRequest仅匹配执行器请求,因此并非所有请求()都会在答案中添加此澄清,因为Spring选择的类名可能会令人困惑。
                 .requestMatchers(forPort(managementPort)).anonymous()
@EnableWebSecurity
@Configuration
public class WebSecurityAdapter extends WebSecurityConfigurerAdapter {
  /**
   * Puerto de administración por donde escucha Actuator.
   */
  @Value("${management.server.port}")
  private int managementPort;
  /*
   * (non-Javadoc)
   * 
   * @see org.springframework.security.config.annotation.web.configuration.
   * WebSecurityConfigurerAdapter#configure(org.springframework.security.config.
   * annotation.web.builders.WebSecurity)
   */
  @Override
  public void configure(WebSecurity web) throws Exception {
    web.ignoring().requestMatchers(forPort(managementPort));
  }
  /**
   * @param port
   *          Puerto que se desea comparar con el puerto de la respuesta http.
   * @return Verdadero si el puerto de la respuesta http es igual al puerto
   *         especificado.
   */
  private RequestMatcher forPort(int port) {
    return (HttpServletRequest request) -> {
      return port == request.getLocalPort();
    };
  }
}