'Definición de frijol no válido' al realizar la migración de primavera de arranque 2.0.6 a 2.1.0 con EvaluationContextExtensionSupport y costumbre PermissionEvaluator

Sebastiaan van den Broek:

En la primavera de arranque 2.1.0 EvaluationContextExtensionSupportes obsoleto y https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/repository/query/spi/EvaluationContextExtensionSupport.html dice a Implementar EvaluationContextExtension directamente

A pesar de que sólo está en desuso, al instante de comenzar su defecto en esta actualización con este StackTrace:

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

Yo no anulan explícitamente esta frijol, así que supongo que esto es sólo un efecto secundario de lo que estamos haciendo en nuestro código actual. Si hago permitir frijol con anulando spring.main.allow-bean-definition-overriding=truesegún https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.1-Release-Notes#bean-overriding entonces simplemente obtener otra excepción.

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]

Sin embargo, no quiero ni para anular cualquier comportamiento frijol, el objetivo es conseguir un evaluador permiso personalizado a trabajar de nuevo el camino de Primavera destina el mismo trabajo.

Así es como lo hizo el trabajo en la última versión:

En la primavera de arranque 2.0.6 tuvimos el siguiente para conseguir nuestra clase PermissionEvaluator personalizado para el trabajo:

Una clase que se extendía 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) {
        };
    }
}

Y luego una clase donde se crea el manejador de expresión con nuestro evaluador permiso, y con un @Bean con una EvaluationContextExtension

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();
    }
}

Y por último tenemos esto en una clase de otra manera casi vacío:

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

Esto se debe a que el evaluador de permisos personalizado no se aplicaba a todos los métodos si sólo hay que poner esto en la MethodSecurityConfigurationclase. El servidor en cuestión es un servidor de recursos de oauth2 por lo que hacemos todo lo que no configure otro lugar del WebSecurityConfigurerAdapter. También implementamos nuestra propia UserDetailsy extendemos el DefaultUserAuthenticationConverter, si esto es de alguna manera relevante para la nueva solución.

He tratado de implementar EvaluationContextExtensionla clase directamente, como se indica en el aviso de desaprobación. Es sólo una simple modificación cambiando la interfaz se extiende a implements EvaluationContextExtension. También he intentado cambiar al paquete aparentemente más recienteorg.springframework.data.spel.spi

He intentado borrar nuestra propia SecurityEvaluationContextExtensiony volviendo https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/data/repository/query/SecurityEvaluationContextExtension.html como un grano directamente pero por alguna razón ese paquete de datos no está disponible en la primavera de arranque 2.1.0

He intentado sólo la eliminación de la definición de ese frijol por completo.

Todas estas cosas dan lugar a varios 'definición de frijol no válidos' errores en el arranque.

¿Alguien sabe dónde encontrar una guía de migración o cualquier otro recurso sobre cómo se supone que funciona ahora?

Sólo por el bien de referencia, el actual CustomPermissionEvaluatorclase:

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
    }
}

Y un ejemplo de cómo se usa:

public interface ProjectRepository extends PagingAndSortingRepository<Project, UUID> {

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

Tomé su código y creado una aplicación de ejemplo de ella. He publicado aquí:

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

Su @EnableGlobalMethodSecurityanotación está en WebSecurityConfigurerAdapter. También tiene una clase que amplíe GlobalMethodSecurityConfiguration. Esto puede causar algunos problemas en el arranque de pedidos, a veces, que puede ser lo que está viendo => dos MethodSecurityExpressionHandlers se crean, así como dos EvaluationContextExtensions.

Si este es precisamente el caso o no (supongo que lo es), cuando coincide con su @EnableGlobalMethodSecuritycon su costumbre GlobalMethodSecurityConfiguration, las cosas empezaron a subir bien.

También, sin embargo, parece que su costumbre EvaluationContextExtensiones muy similar a la forma predeterminada Spring Security. Se podría considerar la eliminación de esa clase, así como el método de frijol correspondiente, si es posible, desde la primavera de arranque expone uno de forma automática cuando se tiene spring-boot-starter-securityy spring-security-datacomo dependencias.

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=137890&siteId=1
Recomendado
Clasificación