加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

java – 如何告诉spring security仅为特定端口应用authorizeReq

发布时间:2020-12-15 01:43:21 所属栏目:大数据 来源:网络整理
导读:我们以官方API在端口8080(在我们的虚拟网络之外映射到端口443上的普通HTTPS)的方式配置我们的新微服务(使用Spring-Boot),而一些管理功能在辅助HTTP上端口7979.这些只在虚拟网络中使用,用于监控,负载均衡等. 所有API访问都需要使用OAuth保护,而管理功能应该可

我们以官方API在端口8080(在我们的虚拟网络之外映射到端口443上的普通HTTPS)的方式配置我们的新微服务(使用Spring-Boot),而一些管理功能在辅助HTTP上端口7979.这些只在虚拟网络中使用,用于监控,负载均衡等.

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

    http
        .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER)
        .and()
        .authorizeRequests()
            .antMatchers("/info").anonymous()
            .antMatchers("/health").anonymous()

            .antMatchers(HttpMethod.GET,"/warehouses/**").access(oauthScopeRead)
            .antMatchers(HttpMethod.PUT,"/warehouses/**").access(oauthScopeWrite)

            .anyRequest().denyAll();

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

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

>在公共端口上,要求对所有内容进行身份验证(并且仅在经过身份验证后返回404或403)
>在管理端口上,根本不需要身份验证(对于不是其中一个配置端点的所有内容,返回404).

我在Spring Security Javadocs或reference documentation中找不到任何有关端口的信息.

我能在这做什么?

最佳答案
我找到了解决方案:

这里的authorizeRequests()方法返回一个ExpressionUrlAuthorizationConfigurer< HttpSecurity> .ExpressionInterceptUrlRegistry,它(从其祖先类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();
}

(这是Java 8语法,对于以前的Java版本,您必须在此处编写任何匿名类.)

虽然requestMatchers需要几个这样的匹配器,看起来它们通过OR连接(至少this example suggests这个),因此我使用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,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”公共可达,而不是一切.

你可以用它

                 .requestMatchers(forPort(managementPort)).anonymous()

使这个端口完全未经授权.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读