1- Crear un nuevo MethodExpressionRoot


package com.cpe.custom.security.custom;


import com.cpe.custom.model.Rol;
import com.cpe.custom.util.AuthUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.access.expression.SecurityExpressionRoot;
import org.springframework.security.access.expression.method.MethodSecurityExpressionOperations;
import org.springframework.security.core.Authentication;


import java.util.function.Supplier;


public class CustomMethodSecurityExpressionRoot extends SecurityExpressionRoot implements MethodSecurityExpressionOperations {


   private static Logger logger = LoggerFactory.getLogger(CustomMethodSecurityExpressionRoot.class);


   private Object filterObject;
   private Object returnObject;
   private Object target;


   CustomMethodSecurityExpressionRoot(Authentication a) {
       super(a);
   }


   CustomMethodSecurityExpressionRoot(Supplier<Authentication> authentication) {
       super(authentication);
   }


   public  boolean hasRolActivo(Rol...roles) {
       return AuthUtil.hasRolUsuarioActivo(roles);
   }


   public void setFilterObject(Object filterObject) {
       this.filterObject = filterObject;
   }


   public Object getFilterObject() {
       return filterObject;
   }


   public void setReturnObject(Object returnObject) {
       this.returnObject = returnObject;
   }


   public Object getReturnObject() {
       return returnObject;
   }


   void setThis(Object target) {
       this.target = target;
   }


   public Object getThis() {
       return target;
   }


}

2 – Crear un nuevo MethodExpressionHandler

package com.cpe.custom.security.custom;


import org.aopalliance.intercept.MethodInvocation;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.expression.method.MethodSecurityExpressionOperations;
import org.springframework.security.core.Authentication;


public class CustomMethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler {


  @Override
  protected MethodSecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication, MethodInvocation invocation) {
       CustomMethodSecurityExpressionRoot root = new CustomMethodSecurityExpressionRoot(authentication);
       root.setThis(invocation.getThis());
       root.setPermissionEvaluator(getPermissionEvaluator());
       return root;
  }
}

3 – Crear una nueva clase de configuración

package com.cpe.custom.config;


import com.cpe.custom.security.custom.CustomMethodSecurityExpressionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {


   @Override
   protected MethodSecurityExpressionHandler createExpressionHandler() {
       return new CustomMethodSecurityExpressionHandler();
   }
}

4 – Crear un nuevo WebSecurityExpressionRoot

package com.cpe.custom.security.custom;


import com.cpe.custom.model.Rol;
import com.cpe.custom.util.AuthUtil;
import jakarta.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.expression.WebSecurityExpressionRoot;

import java.util.Arrays;
import java.util.function.Supplier;


public class CustomWebSecurityExpressionRoot extends WebSecurityExpressionRoot {


   private static Logger logger = LoggerFactory.getLogger(CustomWebSecurityExpressionRoot.class);


   private Object filterObject;
   private Object returnObject;
   private Object target;


   public CustomWebSecurityExpressionRoot(Authentication a, FilterInvocation fi) {
       this(() -> a, fi.getRequest());
   }


   public CustomWebSecurityExpressionRoot(Supplier<Authentication> authentication, HttpServletRequest request) {
       super(authentication,request);
   }
   public  boolean hasRolActivo(Rol...roles) {
       return AuthUtil.hasRolUsuarioActivo(roles);
   }
   public void setFilterObject(Object filterObject) {
       this.filterObject = filterObject;
   }


   public Object getFilterObject() {
       return filterObject;
   }


   public void setReturnObject(Object returnObject) {
       this.returnObject = returnObject;
   }


   public Object getReturnObject() {
       return returnObject;
   }


   void setThis(Object target) {
       this.target = target;
   }

   public Object getThis() {
       return target;
   }

}

5 – Crear una nueva WebSecurityExpressionHandler

package com.cpe.custom.security.custom;


import org.springframework.security.access.expression.AbstractSecurityExpressionHandler;
import org.springframework.security.access.expression.SecurityExpressionHandler;
import org.springframework.security.access.expression.SecurityExpressionOperations;
import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.expression.WebSecurityExpressionRoot;
import org.springframework.util.Assert;


public class CustomWebSecurityExpressionHandler extends AbstractSecurityExpressionHandler<FilterInvocation>
       implements SecurityExpressionHandler<FilterInvocation> {


   private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();

   private String defaultRolePrefix = "ROLE_";


   @Override
   protected SecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication,
                                                                       FilterInvocation fi) {
       WebSecurityExpressionRoot root = new CustomWebSecurityExpressionRoot(authentication, fi);
       root.setPermissionEvaluator(getPermissionEvaluator());
       root.setTrustResolver(this.trustResolver);
       root.setRoleHierarchy(getRoleHierarchy());
       root.setDefaultRolePrefix(this.defaultRolePrefix);
       return root;
   }


   /**
    * Sets the {@link AuthenticationTrustResolver} to be used. The default is
    * {@link AuthenticationTrustResolverImpl}.
    * @param trustResolver the {@link AuthenticationTrustResolver} to use. Cannot be
    * null.
    */
   public void setTrustResolver(AuthenticationTrustResolver trustResolver) {
       Assert.notNull(trustResolver, "trustResolver cannot be null");
       this.trustResolver = trustResolver;
   }


   /**
    * <p>
    * Sets the default prefix to be added to
    * {@link org.springframework.security.access.expression.SecurityExpressionRoot#hasAnyRole(String...)}
    * or
    * {@link org.springframework.security.access.expression.SecurityExpressionRoot#hasRole(String)}.
    * For example, if hasRole("ADMIN") or hasRole("ROLE_ADMIN") is passed in, then the
    * role ROLE_ADMIN will be used when the defaultRolePrefix is "ROLE_" (default).
    * </p>
    *
    * <p>
    * If null or empty, then no default role prefix is used.
    * </p>
    * @param defaultRolePrefix the default prefix to add to roles. Default "ROLE_".
    */
   public void setDefaultRolePrefix(String defaultRolePrefix) {
       this.defaultRolePrefix = defaultRolePrefix;
   }
}

6 – Crear una nueva clase de configuración

package com.cpe.custom.config;


import com.cpe.custom.security.custom.CustomWebSecurityExpressionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.access.expression.SecurityExpressionHandler;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration;
import org.springframework.security.web.FilterInvocation;


@Configuration
@EnableWebSecurity
@Order(2)
public class WebSecurityConfig extends WebSecurityConfiguration {

   @Override
   public SecurityExpressionHandler<FilterInvocation> webSecurityExpressionHandler() {
       return new CustomWebSecurityExpressionHandler();
   }
}

7 – Modificar configuración inicial

En la clase de configuración que utilicemos para Spring security, tenemos que poner el parámetro prePostEnabled =false (lo configuramos en el MethodSecurityConfig

</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>@Configuration</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>@EnableWebSecurity@EnableMethodSecurity(prePostEnabled = false,securedEnabled = true)</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><br>

8 – Añadir parámetro de configuración

Para permitir que se sobreescriba el bean delegatingApplicationListener tenemos que añadir en la configuración del proyecto (application.properties)

spring.main.allow-bean-definition-overriding=true