通用 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 可以是 createreadupdatedelete 或任何您喜欢的作为权限字符串一部分的内容。此实现依赖于通过 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();
}