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