gpt4 book ai didi

java - 使用 EvaluationContextExtensionSupport 和自定义 PermissionEvaluator 将 Spring Boot 2.0.6 迁移到 2.1.0 时出现“无效的 bean 定义”

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:49:38 24 4
gpt4 key购买 nike

在 Spring Boot 2.1.0 中 EvaluationContextExtensionSupport 被弃用并且 https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/repository/query/spi/EvaluationContextExtensionSupport.html直接实现 EvaluationContextExtension

即使它只是被弃用,它也会立即开始使用此堆栈跟踪进行此升级失败:

Caused by: org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name 'methodSecurityInterceptor' defined in class path resource [org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfiguration.class]: Cannot register bean definition [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration; factoryMethodName=methodSecurityInterceptor; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfiguration.class]] for bean 'methodSecurityInterceptor': There is already [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=methodSecurityConfiguration; factoryMethodName=methodSecurityInterceptor; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [ournamespace/configuration/MethodSecurityConfiguration.class]] bound.
at org.springframework.beans.factory.support.DefaultListableBeanFactory.registerBeanDefinition(DefaultListableBeanFactory.java:894)
at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForBeanMethod(ConfigurationClassBeanDefinitionReader.java:274)
at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForConfigurationClass(ConfigurationClassBeanDefinitionReader.java:141)
...and so on

我没有显式地覆盖这个 bean,所以我猜这只是我们在当前代码中所做的事情的副作用。如果我根据 https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.1-Release-Notes#bean-overriding 允许使用 spring.main.allow-bean-definition-overriding=true 覆盖 bean然后我只是得到另一个异常。

java.lang.IllegalStateException: Duplicate key org.springframework.data.spel.ExtensionAwareEvaluationContextProvider$EvaluationContextExtensionAdapter@10dfbbbb at java.util.stream.Collectors.lambda$throwingMerger$0(Collectors.java:133) ~[na:1.8.0_162]

但是,我什至不想覆盖任何 bean 行为,目标是让自定义权限评估器再次按照 Spring 预期的方式工作。

这是它在上一个版本中的工作方式:

在 Spring Boot 2.0.6 中,我们有以下内容来让我们的自定义 PermissionEvaluator 类工作:

扩展EvaluationContextExtensionSupport的类

import org.springframework.data.repository.query.spi.EvaluationContextExtensionSupport;
import org.springframework.security.access.expression.SecurityExpressionRoot;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;

public class SecurityEvaluationContextExtension extends EvaluationContextExtensionSupport {

@Override
public String getExtensionId() {
return "security";
}

@Override
public SecurityExpressionRoot getRootObject() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
return new SecurityExpressionRoot(authentication) {
};
}
}

然后是一个类,其中使用我们的权限评估器创建表达式处理程序,并使用带有 EvaluationContextExtension

的 @Bean
import ournamespace.security.CustomPermissionEvaluator;
import ournamespace.security.SecurityEvaluationContextExtension;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.repository.query.spi.EvaluationContextExtension;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;

@Configuration
@RequiredArgsConstructor
public class MethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {

private final CustomPermissionEvaluator permissionEvaluator;

@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
DefaultMethodSecurityExpressionHandler expressionHandler =
new DefaultMethodSecurityExpressionHandler();
expressionHandler.setPermissionEvaluator(permissionEvaluator);
return expressionHandler;
}

@Bean
EvaluationContextExtension securityExtension() {
return new SecurityEvaluationContextExtension();
}
}

最后我们在一个几乎是空的类中得到了这个:

@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
...
}

这是因为如果我们只是将其放在 MethodSecurityConfiguration 类中,自定义权限评估器就不会应用于所有方法。有问题的服务器是一个 oauth2 资源服务器,因此我们没有在 WebSecurityConfigurerAdapter 中配置任何其他内容。我们还实现了自己的 UserDetails 并扩展了 DefaultUserAuthenticationConverter,如果这与新解决方案有任何相关的话。

我已尝试直接实现 EvaluationContextExtension 类,如弃用警告中所述。这只是一个简单的修改,将扩展接口(interface)更改为 implements EvaluationContextExtension。我还尝试更改为看似较新的包 org.springframework.data.spel.spi

我尝试删除我们自己的 SecurityEvaluationContextExtension 并返回 https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/data/repository/query/SecurityEvaluationContextExtension.html直接作为 bean 但由于某些原因,数据包在 Spring Boot 2.1.0 中不可用

我试过完全删除那个 bean 的定义。

所有这些都会导致启动时出现各种“无效的 bean 定义”错误。

有谁知道在哪里可以找到迁移指南或任何其他资源,了解它现在应该如何工作?

仅供引用,实际的 CustomPermissionEvaluator 类:

import ournamespace.configuration.Constants;
import ournamespace.exception.InternalException;
import ournamespace.model.Account;
import ournamespace.model.Member;
import ournamespace.model.Project;
import ournamespace.repository.MemberRepository;
import ournamespace.service.ServiceUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;

import java.io.Serializable;

import static ournamespace.model.MemberStatus.JOINED;
import static ournamespace.model.ProjectRole.*;

@RequiredArgsConstructor
@Component
public class CustomPermissionEvaluator implements PermissionEvaluator {

private final MemberRepository memberRepository;

@Override
public boolean hasPermission(Authentication auth, Object targetDomainObject, Object permission) {
if (targetDomainObject == null)
return false;

if (!(permission instanceof String))
return false;

if (auth == null)
return false;

Account account = ServiceUtil.getAccount(auth);

if (targetDomainObject instanceof Project)
return hasPermissionOnProject(account, (Project) targetDomainObject, (String) permission);
//and so on
}
}

以及如何使用它的示例:

public interface ProjectRepository extends PagingAndSortingRepository<Project, UUID> {

@Override
@PreAuthorize("hasPermission(#project, " + Constants.WRITE + ")")
<S extends Project> S save(@Param("project") S project);
}

最佳答案

我使用了您的代码并从中创建了一个示例应用程序。我把它贴在这里:

https://github.com/jzheaux/stackoverflow-53410526

您的 @EnableGlobalMethodSecurity 注释在 WebSecurityConfigurerAdapter 上。您还有一个扩展 GlobalMethodSecurityConfiguration 的类。这有时会在启动时导致一些排序问题,这可能就是您所看到的 => 创建了两个 MethodSecurityExpressionHandler 以及两个 EvaluationContextExtension

无论情况是否如此(我猜是这样),当我将您的 @EnableGlobalMethodSecurity 与您的自定义 GlobalMethodSecurityConfiguration 匹配时,一切都开始正常.

此外,您的自定义 EvaluationContextExtension 似乎与 Spring Security 默认值非常相似。如果可以的话,您可能会考虑删除该类以及相应的 bean 方法,因为当您拥有 spring-boot-starter-securityspring-security-data 时,Spring Boot 会自动公开一个 作为依赖。

关于java - 使用 EvaluationContextExtensionSupport 和自定义 PermissionEvaluator 将 Spring Boot 2.0.6 迁移到 2.1.0 时出现“无效的 bean 定义”,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53410526/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com