通用 HTTP 安全路径匹配器,在安全表达式中引用匹配路径
Generic HTTP security path matcher, reference matched path in security expression
现在,借助 Spring 安全性的 HttpSecurity
,我们能够将通配符路径限制为特定的 roles/authorities:
.mvcMatchers(POST, "/users").hasAuthority("create:users")
.mvcMatchers(PUT, "/users/{id}").hasAuthority("update:users")
有没有简单的方法:
.mvcMatchers(POST, "/{whateverGoesHere}").hasAuthority("create:${whateverGoesHere}")
.mvcMatchers(PUT, "/{whateverGoesHere}/{id}").hasAuthority("update:${whateverGoesHere}")
?
它不一定是使用 configure(HttpSecurity http)
API 的解决方案,我只是在寻找一种简单的方法来同时为多个 REST 实体生成授权规则。
我认为您的代码中不应包含隐藏行为。如果开发人员想要添加一个新的端点并希望它需要一些权限,那么应该有意识地这样做。否则,如果开发人员打算添加一个开放端点并想知道为什么它是安全的,它可能会成为调试噩梦。
但是您可以为所有未指定的端点添加默认行为。该行为可能是拒绝访问。这样,每个开发人员都必须添加某种访问授权条目。那样就保证不被遗忘,但还是有意为之。
...
.mvcMatchers(POST, "/users").hasAuthority("create:users")
.mvcMatchers(PUT, "/users/{id}").hasAuthority("update:users")
.anyRequest().denyAll()
至少可以说,这显然是一个更高级的场景。然而,Spring Security 5.5 的改进引入了新的 AuthorizationManager
接口和 http.authorizeHttpRequests()
方法来配置使用它的授权规则。有关详细信息,请参阅参考文档中的 The AuthorizationManager。它非常强大!我相信这可能是您用例的最佳选择。
Spring 安全性中有许多可用的实现,可用于构建复合 and/or 委托实现。这是一个使用您的约定的示例:
public final class ResourceAuthorizationManager implements AuthorizationManager<RequestAuthorizationContext> {
private final String action;
public ResourceAuthorizationManager(String action) {
this.action = action;
}
@Override
public AuthorizationDecision check(Supplier<Authentication> authentication, RequestAuthorizationContext context) {
AuthorizationManager<RequestAuthorizationContext> delegate =
AuthorityAuthorizationManager.hasAuthority(createAuthority(context));
return delegate.check(authentication, context);
}
private String createAuthority(RequestAuthorizationContext context) {
String resource = context.getVariables().get("resource");
return String.format("%s:%s", this.action, resource);
}
}
action
可以是 create
、read
、update
、delete
或任何您喜欢的作为权限字符串一部分的内容。此实现依赖于通过 RequestAuthorizationContext
提供的 URI 变量。碰巧的是,有一个现有的实现 (RequestMatcherDelegatingAuthorizationManager
) 可以处理这种情况。它实际上是 Spring 安全 DSL 中处理 .mvcMatchers()
授权规则的那个。这是一个使用它委托给上面的 convention-based AuthorizationManager
的示例:
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authorizeHttpRequests) -> authorizeHttpRequests
.mvcMatchers(HttpMethod.POST, "/{resource}").access(new ResourceAuthorizationManager("create"))
.mvcMatchers(HttpMethod.PUT, "/{resource}/{id}").access(new ResourceAuthorizationManager("update"))
.anyRequest().authenticated()
)
.formLogin(Customizer.withDefaults());
return http.build();
}
现在,借助 Spring 安全性的 HttpSecurity
,我们能够将通配符路径限制为特定的 roles/authorities:
.mvcMatchers(POST, "/users").hasAuthority("create:users")
.mvcMatchers(PUT, "/users/{id}").hasAuthority("update:users")
有没有简单的方法:
.mvcMatchers(POST, "/{whateverGoesHere}").hasAuthority("create:${whateverGoesHere}")
.mvcMatchers(PUT, "/{whateverGoesHere}/{id}").hasAuthority("update:${whateverGoesHere}")
?
它不一定是使用 configure(HttpSecurity http)
API 的解决方案,我只是在寻找一种简单的方法来同时为多个 REST 实体生成授权规则。
我认为您的代码中不应包含隐藏行为。如果开发人员想要添加一个新的端点并希望它需要一些权限,那么应该有意识地这样做。否则,如果开发人员打算添加一个开放端点并想知道为什么它是安全的,它可能会成为调试噩梦。
但是您可以为所有未指定的端点添加默认行为。该行为可能是拒绝访问。这样,每个开发人员都必须添加某种访问授权条目。那样就保证不被遗忘,但还是有意为之。
...
.mvcMatchers(POST, "/users").hasAuthority("create:users")
.mvcMatchers(PUT, "/users/{id}").hasAuthority("update:users")
.anyRequest().denyAll()
至少可以说,这显然是一个更高级的场景。然而,Spring Security 5.5 的改进引入了新的 AuthorizationManager
接口和 http.authorizeHttpRequests()
方法来配置使用它的授权规则。有关详细信息,请参阅参考文档中的 The AuthorizationManager。它非常强大!我相信这可能是您用例的最佳选择。
Spring 安全性中有许多可用的实现,可用于构建复合 and/or 委托实现。这是一个使用您的约定的示例:
public final class ResourceAuthorizationManager implements AuthorizationManager<RequestAuthorizationContext> {
private final String action;
public ResourceAuthorizationManager(String action) {
this.action = action;
}
@Override
public AuthorizationDecision check(Supplier<Authentication> authentication, RequestAuthorizationContext context) {
AuthorizationManager<RequestAuthorizationContext> delegate =
AuthorityAuthorizationManager.hasAuthority(createAuthority(context));
return delegate.check(authentication, context);
}
private String createAuthority(RequestAuthorizationContext context) {
String resource = context.getVariables().get("resource");
return String.format("%s:%s", this.action, resource);
}
}
action
可以是 create
、read
、update
、delete
或任何您喜欢的作为权限字符串一部分的内容。此实现依赖于通过 RequestAuthorizationContext
提供的 URI 变量。碰巧的是,有一个现有的实现 (RequestMatcherDelegatingAuthorizationManager
) 可以处理这种情况。它实际上是 Spring 安全 DSL 中处理 .mvcMatchers()
授权规则的那个。这是一个使用它委托给上面的 convention-based AuthorizationManager
的示例:
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authorizeHttpRequests) -> authorizeHttpRequests
.mvcMatchers(HttpMethod.POST, "/{resource}").access(new ResourceAuthorizationManager("create"))
.mvcMatchers(HttpMethod.PUT, "/{resource}/{id}").access(new ResourceAuthorizationManager("update"))
.anyRequest().authenticated()
)
.formLogin(Customizer.withDefaults());
return http.build();
}