Spring Security如何让ROLE_ADMIN无需逐页配置即可访问所有@RolesAllowed受限资源
Spring Security 全局管理员角色绕过权限校验实现方案
我们直接采用你优先选择的第一种方案,通过Spring Security的方法安全授权逻辑扩展实现,无需修改现有业务注解配置,兼容@RolesAllowed、@Secured、@PreAuthorize/@PostAuthorize全部注解类型。
实现原理
Spring Security的方法安全校验最终会调用授权管理器做权限判定,我们只需要扩展该逻辑,在执行原有校验规则前,先判断当前用户是否持有ROLE_ADMIN角色,如果持有直接返回校验通过即可。该方式是Spring官方支持的原生扩展方案,对业务代码无侵入。
实现步骤(基于Spring Security 5.7+/6.x 版本,推荐使用AuthorizationManager实现)
1. 自定义通用授权管理器
import org.springframework.security.authorization.AuthorizationDecision; import org.springframework.security.authorization.AuthorizationManager; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import java.util.function.Supplier; public class AdminBypassAuthorizationManager<T> implements AuthorizationManager<T> { private final AuthorizationManager<T> delegate; private static final String ADMIN_ROLE = "ROLE_ADMIN"; public AdminBypassAuthorizationManager(AuthorizationManager<T> delegate) { this.delegate = delegate; } @Override public AuthorizationDecision check(Supplier<Authentication> authenticationSupplier, T object) { Authentication auth = authenticationSupplier.get(); // 优先判断是否是管理员,是则直接放行 if (auth != null && auth.isAuthenticated()) { for (GrantedAuthority authority : auth.getAuthorities()) { if (ADMIN_ROLE.equals(authority.getAuthority())) { return new AuthorizationDecision(true); } } } // 不是管理员则执行原有校验逻辑 return delegate.check(authenticationSupplier, object); } }
2. 方法安全配置替换默认授权管理器
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.authorization.method.PreAuthorizeAuthorizationManager; import org.springframework.security.authorization.method.SecuredAuthorizationManager; import org.springframework.security.authorization.method.Jsr250AuthorizationManager; @Configuration // 开启你需要的注解类型支持,这里开了三类注解的开关 @EnableMethodSecurity(jsr250Enabled = true, securedEnabled = true, prePostEnabled = true) public class MethodSecurityConfig { // 替换@PreAuthorize/@PostAuthorize注解的授权管理器 @Bean public PreAuthorizeAuthorizationManager preAuthorizeAuthorizationManager() { return new AdminBypassAuthorizationManager<>(new PreAuthorizeAuthorizationManager()); } // 替换@Secured注解的授权管理器 @Bean public SecuredAuthorizationManager securedAuthorizationManager() { return new AdminBypassAuthorizationManager<>(new SecuredAuthorizationManager()); } // 替换@RolesAllowed注解的授权管理器 @Bean public Jsr250AuthorizationManager jsr250AuthorizationManager() { return new AdminBypassAuthorizationManager<>(new Jsr250AuthorizationManager()); } }
低版本Spring Security兼容方案(5.7之前版本)
如果使用的是旧版本Spring Security,可以通过自定义AccessDecisionVoter实现相同效果:
- 自定义管理员权限投票器
import org.springframework.security.access.AccessDecisionVoter; import org.springframework.security.access.ConfigAttribute; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import java.util.Collection; public class AdminRoleVoter implements AccessDecisionVoter<Object> { @Override public boolean supports(ConfigAttribute attribute) { return true; } @Override public boolean supports(Class<?> clazz) { return true; } @Override public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) { if (authentication == null) { return ACCESS_DENIED; } for (GrantedAuthority authority : authentication.getAuthorities()) { if ("ROLE_ADMIN".equals(authority.getAuthority())) { return ACCESS_GRANTED; } } return ACCESS_ABSTAIN; } }
- 将该投票器全局注册到方法安全的投票器列表中即可生效。
效果说明
配置完成后,所有加了权限注解的方法、页面接口,只要用户持有ROLE_ADMIN角色,无论注解里配置的角色要求是什么,都会直接放行,不需要修改任何原有业务代码的注解配置。
内容的提问来源于stack exchange,提问作者Avec
相关产品推荐
相关产品推荐

