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