You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在自定义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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 21:53:21