我怎样才能告诉Spring Security仅对特定端口应用authorizeRequests? [英] How can I tell spring security to apply authorizeRequests just for a specific port?
问题描述
我们以新的微服务(使用Spring-Boot)配置了以下方式:官方API位于端口8080上(该端口映射到虚拟网络之外,映射至端口443上的常规HTTPS),而某些管理功能处于启用状态辅助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). /p>
由于公共端口上没有/info
或/health
,这些返回404给未授权用户,而其他所有返回401.我对此不满意,并且希望拥有
- 在公共端口上,要求对所有内容进行身份验证(并且仅在身份验证后返回404或403)
- 在管理端口上,完全不需要身份验证(对于不是已配置端点之一的所有内容,返回404).
我在Spring Security Javadocs或解决方案
我找到了解决方法:
此处的authorizeRequests()
方法返回一个ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry
,它在某些antMatchers
方法旁边(来自其祖先类AbstractRequestMatcherRegistry)还有一个通用的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版本,您必须在此处编写一个匿名类.)
虽然 这不能完全反映问题:在此managementPort只是"/info"和"/health"公共可访问的,而不是所有内容. 您可以使用此 以使此端口完全未经授权. We configured our new micro service (using Spring-Boot) in a way that the official API is on port 8080 (which is be mapped outside of our virtual network to normal HTTPS on port 443), while some management functions are on a secondary HTTP port 7979. These are only used inside the virtual network, and used for monitoring, loadbalancing etc. All API access needs to be secured with OAuth, while the management functions should be accessible freely inside the network. So we configured Spring security this way (http is a HttpSecurity object): This has the effect on both ports: As there is no I couldn't find anything about ports in the Spring Security Javadocs or reference documentation. What can I do here? I found a solution: The (This is Java 8 syntax, with previous Java versions you'll had to write an anyonymous class here.) While The final code looked like this: This does not fully reflect the question: the managementPort has here just "/info" and "/health" public reachable, instead of everything. You could use this to make this port fully unauthorized. 这篇关于我怎样才能告诉Spring Security仅对特定端口应用authorizeRequests?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!requestMatchers
需要几个这样的匹配器,但是看起来它们是通过OR连接的(至少 .requestMatchers(forPort(managementPort)).anonymous()
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
and /health
are unauthorized, while /warehouses
needs authentication, and everything else also needs authentication (returns 401, but when invoking with authentication, it returns 403)./info
or /health
on the public port, these return 404 for unauthorized users, while everything else returns 401. I'm unsatisfied with this and would like to have
authorizeRequests()
method here returns an ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry
, which has (from its ancestor class AbstractRequestMatcherRegistry) beside some antMatchers
methods also a generic requestMatchers()
method, which takes one or more RequestMatcher
objects. It turns out this is an interface I can implement myself:/**
* 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();
}
requestMatchers
takes several such matchers, it looks like those are connected by OR (at least this example suggests this), thus I used an AndRequestMatcher to connect it to the matcher for the path (and HTTP method)).@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(); };
}
.requestMatchers(forPort(managementPort)).anonymous()