Spring Boot实现需同时拥有ADMIN和EXECUTIVE角色的接口访问控制
Spring Boot中实现需同时拥有ADMIN和EXECUTIVE角色的接口权限控制
下面是几种实用的实现方案,覆盖不同场景需求:
方法1:使用Spring Security内置表达式(最简便)
Spring Security提供了hasAllRoles()表达式,可直接校验用户是否同时拥有指定的所有角色,注意默认角色前缀为ROLE_,若你的角色未使用该前缀,需先配置关闭或手动添加。
1.1 方法级别注解(推荐)
直接在Controller接口方法上标注@PreAuthorize,精准控制单接口权限:
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class SecureController { // 要求用户同时拥有ADMIN和EXECUTIVE角色(若角色带ROLE_前缀,需写成hasAllRoles('ROLE_ADMIN', 'ROLE_EXECUTIVE')) @PreAuthorize("hasAllRoles('ADMIN', 'EXECUTIVE')") @GetMapping("/api/dual-role/secure") public String accessDualRoleResource() { return "仅同时具备ADMIN和EXECUTIVE角色的用户可访问此接口"; } }
若需关闭默认角色前缀,在Security配置类中添加如下配置:
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.config.annotation.web.builders.HttpSecurity; import org.springframework.security.web.SecurityFilterChain; @Configuration @EnableMethodSecurity // 开启方法级安全校验 public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth.anyRequest().authenticated()) .roleHierarchy(hierarchy -> hierarchy.rolePrefix("")); // 关闭ROLE_前缀 return http.build(); } }
1.2 全局路径配置
若要对一批路径统一设置权限,可在Security配置类中通过路径匹配指定表达式:
@Configuration @EnableMethodSecurity public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth .requestMatchers("/api/dual-role/**").access("hasAllRoles('ADMIN', 'EXECUTIVE')") .anyRequest().authenticated() ) .roleHierarchy(hierarchy -> hierarchy.rolePrefix("")); return http.build(); } }
方法2:自定义注解(复用性更强)
如果需要在多个接口复用"同时拥有ADMIN和EXECUTIVE"的权限规则,可自定义注解封装校验逻辑:
步骤1:定义自定义注解
import org.springframework.security.access.prepost.PreAuthorize; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @PreAuthorize("hasAllRoles('ADMIN', 'EXECUTIVE')") public @interface RequireAdminAndExecutive { }
步骤2:在接口上使用注解
@RestController public class SecureController { @RequireAdminAndExecutive @GetMapping("/api/dual-role/secure") public String accessDualRoleResource() { return "仅同时具备ADMIN和EXECUTIVE角色的用户可访问此接口"; } }
方法3:自定义投票器(复杂场景适配)
若角色校验逻辑需动态调整(比如从数据库读取规则),可自定义AccessDecisionVoter实现更灵活的权限控制:
步骤1:实现投票器
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 DualRoleVoter implements AccessDecisionVoter<Object> { private static final String REQUIRED_ROLE_ADMIN = "ADMIN"; private static final String REQUIRED_ROLE_EXECUTIVE = "EXECUTIVE"; private static final String RULE_KEY = "ADMIN_AND_EXECUTIVE"; @Override public boolean supports(ConfigAttribute attribute) { return RULE_KEY.equals(attribute.getAttribute()); } @Override public boolean supports(Class<?> clazz) { return true; } @Override public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) { boolean hasAdmin = false; boolean hasExecutive = false; for (GrantedAuthority authority : authentication.getAuthorities()) { if (REQUIRED_ROLE_ADMIN.equals(authority.getAuthority())) hasAdmin = true; if (REQUIRED_ROLE_EXECUTIVE.equals(authority.getAuthority())) hasExecutive = true; } return (hasAdmin && hasExecutive) ? ACCESS_GRANTED : ACCESS_DENIED; } }
步骤2:注册投票器到Security配置
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.access.AccessDecisionManager; import org.springframework.security.access.vote.AffirmativeBased; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.web.SecurityFilterChain; import java.util.List; @Configuration @EnableMethodSecurity public class SecurityConfig { @Bean public AccessDecisionManager accessDecisionManager() { return new AffirmativeBased(List.of(new DualRoleVoter())); } @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth .requestMatchers("/api/dual-role/**").access("ADMIN_AND_EXECUTIVE") .anyRequest().authenticated() ) .accessDecisionManager(accessDecisionManager()); return http.build(); } }
内容的提问来源于stack exchange,提问作者Emmanuel Mbewe
相关产品推荐
相关产品推荐

