如何在自定义SecurityExpressionRoot中使用Spring应用配置属性?
最优实现方案
核心思路是通过构造注入将EnvironmentConfig传递到自定义的SecurityExpressionRoot中,同时自定义SecurityExpressionHandler完成依赖注入的衔接,既保证Spring Security表达式体系正常工作,又能安全使用配置变量做授权决策。
步骤1:确保配置类生效
先确认EnvironmentConfig已被Spring容器管理,在启动类上添加@EnableConfigurationProperties(EnvironmentConfig.class),或用@ConfigurationPropertiesScan扫描配置类所在包:
@SpringBootApplication @EnableConfigurationProperties(EnvironmentConfig.class) public class YourApplication { public static void main(String[] args) { SpringApplication.run(YourApplication.class, args); } }
步骤2:改造自定义SecurityExpressionRoot
给自定义表达式根类添加构造方法注入EnvironmentConfig,并实现授权逻辑方法:
import org.springframework.security.access.expression.SecurityExpressionRoot; import org.springframework.security.access.expression.method.MethodSecurityExpressionOperations; import org.springframework.security.core.Authentication; public class CustomSecurityExpressionRoot extends SecurityExpressionRoot implements MethodSecurityExpressionOperations { private final EnvironmentConfig environmentConfig; private Object filterObject; private Object returnObject; // 构造注入EnvironmentConfig public CustomSecurityExpressionRoot(Authentication authentication, EnvironmentConfig environmentConfig) { super(authentication); this.environmentConfig = environmentConfig; } // 自定义授权方法:判断用户所属组织是否为homeOrg public boolean isHomeOrgUser() { // 从当前用户信息中获取组织ID(根据实际业务调整) UUID userOrgId = getCurrentUserOrgId(); return environmentConfig.getHomeOrg().equals(userOrgId); } // 实现MethodSecurityExpressionOperations的必要方法 @Override public void setFilterObject(Object filterObject) { this.filterObject = filterObject; } @Override public Object getFilterObject() { return filterObject; } @Override public void setReturnObject(Object returnObject) { this.returnObject = returnObject; } @Override public Object getReturnObject() { return returnObject; } @Override public Object getThis() { return this; } // 辅助方法:获取当前用户的组织ID private UUID getCurrentUserOrgId() { // 示例:假设自定义UserDetails包含orgId字段 YourUserDetails userDetails = (YourUserDetails) this.getPrincipal(); return userDetails.getOrgId(); } }
步骤3:自定义SecurityExpressionHandler
创建自定义表达式处理器,在生成CustomSecurityExpressionRoot实例时注入EnvironmentConfig:
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler; import org.springframework.security.access.expression.method.MethodSecurityExpressionOperations; import org.springframework.security.core.Authentication; import java.lang.reflect.Method; public class CustomMethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler { private final EnvironmentConfig environmentConfig; // 构造注入EnvironmentConfig public CustomMethodSecurityExpressionHandler(EnvironmentConfig environmentConfig) { this.environmentConfig = environmentConfig; } @Override protected MethodSecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication, MethodInvocation invocation) { CustomSecurityExpressionRoot root = new CustomSecurityExpressionRoot(authentication, environmentConfig); root.setPermissionEvaluator(getPermissionEvaluator()); root.setTrustResolver(getTrustResolver()); root.setRoleHierarchy(getRoleHierarchy()); return root; } }
步骤4:配置SecurityFilterChain与方法安全
在Security配置类中注册自定义处理器,并配置到HTTP安全或方法安全体系:
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 { private final EnvironmentConfig environmentConfig; // 构造注入EnvironmentConfig public SecurityConfig(EnvironmentConfig environmentConfig) { this.environmentConfig = environmentConfig; } // 注册自定义表达式处理器 @Bean public CustomMethodSecurityExpressionHandler customMethodSecurityExpressionHandler() { return new CustomMethodSecurityExpressionHandler(environmentConfig); } // 配置HTTP安全规则 @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth // 用自定义表达式保护指定接口 .requestMatchers("/api/home-org/**").access("@customMethodSecurityExpressionHandler.isHomeOrgUser()") .anyRequest().authenticated() ); return http.build(); } }
实际使用
在接口方法上直接使用自定义授权表达式:
@RestController @RequestMapping("/api/home-org") public class HomeOrgController { @GetMapping("/info") @PreAuthorize("isHomeOrgUser()") public String getHomeOrgInfo() { return "Home Org专属内容"; } }
内容的提问来源于stack exchange,提问作者Vilican
相关产品推荐
相关产品推荐

