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

如何自定义ExpressionInterceptURL动态管理InfoPack系列URL访问权限

Dynamic URL Access Control for Scalable InfoPacks in Spring Security

Great question—this is a super common pain point when dealing with dynamic security rules that need to scale as your application grows. Let’s break down how to solve this without having to redeploy every time you add a new InfoPack:

1. Use a Custom FilterInvocationSecurityMetadataSource for Dynamic Rule Lookup

Spring Security’s FilterInvocationSecurityMetadataSource is built to fetch security rules at runtime, which is perfect for your use case. Here’s how to implement it:

  • First, create a component that implements this interface. It will parse incoming requests, extract the InfoPack name, and fetch the required role (from a database, config center, or cached store):
@Component
public class DynamicInfoPackSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

    private final InfoPackPermissionService permissionService;

    // Inject a service to fetch up-to-date permission mappings (e.g., from a database)
    public DynamicInfoPackSecurityMetadataSource(InfoPackPermissionService permissionService) {
        this.permissionService = permissionService;
    }

    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
        FilterInvocation filterInvocation = (FilterInvocation) object;
        String requestUrl = filterInvocation.getRequestUrl();

        // Match the InfoPack path pattern and extract the pack name
        Matcher pathMatcher = Pattern.compile("/InfoPacks/(\\w+)/.*").matcher(requestUrl);
        if (pathMatcher.matches()) {
            String infoPackName = pathMatcher.group(1);
            String requiredRole = "ROLE_INFOPACK" + infoPackName.toUpperCase();

            // Validate the role exists (optional but recommended)
            if (permissionService.isRoleRegistered(requiredRole)) {
                return SecurityConfig.createList(requiredRole);
            }
        }

        // Return null to fall back to default security rules for non-InfoPack paths
        return null;
    }

    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null; // Not needed for our dynamic use case
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return FilterInvocation.class.isAssignableFrom(clazz);
    }
}

2. Configure WebSecurity to Use Your Dynamic Metadata Source

Update your WebSecurityConfig to replace hardcoded antMatchers with your custom metadata source. Use an ObjectPostProcessor to attach it to Spring’s FilterSecurityInterceptor:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

    private final DynamicInfoPackSecurityMetadataSource dynamicMetadataSource;

    public WebSecurityConfig(DynamicInfoPackSecurityMetadataSource dynamicMetadataSource) {
        this.dynamicMetadataSource = dynamicMetadataSource;
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .anyRequest().authenticated() // Base rule for all requests
            )
            // Attach our dynamic metadata source to the security interceptor
            .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
                @Override
                public <O extends FilterSecurityInterceptor> O postProcess(O interceptor) {
                    interceptor.setSecurityMetadataSource(dynamicMetadataSource);
                    // Use the default AccessDecisionManager or replace with your own if needed
                    // interceptor.setAccessDecisionManager(customAccessDecisionManager());
                    return interceptor;
                }
            });

        // Add other configs like authentication providers, password encoders, etc.
        return http.build();
    }
}

3. Make Permissions Dynamically Updatable

To avoid redeploys when adding new InfoPacks:

  • Store the InfoPack-to-role mapping in a database (e.g., a table like info_pack_permissions with columns info_pack_name and required_role)
  • Implement InfoPackPermissionService to fetch the latest mappings from the database. Add caching (e.g., Redis) for performance, and invalidate the cache whenever a new InfoPack is added
  • This way, every incoming request will check the latest permissions without needing code changes or restarts

4. Alternative: Use a Custom Security Expression

If you prefer working with Spring Security expressions, create a custom bean to check permissions dynamically:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

    private final InfoPackPermissionService permissionService;

    public WebSecurityConfig(InfoPackPermissionService permissionService) {
        this.permissionService = permissionService;
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                // Use our custom expression for InfoPack paths
                .requestMatchers("/InfoPacks/**").access("@infoPackSecurityChecker.hasAccess(request, authentication)")
                .anyRequest().authenticated()
            );
        return http.build();
    }

    @Bean
    public InfoPackSecurityChecker infoPackSecurityChecker() {
        return new InfoPackSecurityChecker(permissionService);
    }
}

// Custom checker bean
@Component
public class InfoPackSecurityChecker {

    private final InfoPackPermissionService permissionService;

    public InfoPackSecurityChecker(InfoPackPermissionService permissionService) {
        this.permissionService = permissionService;
    }

    public boolean hasAccess(HttpServletRequest request, Authentication authentication) {
        String requestUrl = request.getRequestURI();
        Matcher pathMatcher = Pattern.compile("/InfoPacks/(\\w+)/.*").matcher(requestUrl);

        if (pathMatcher.matches()) {
            String infoPackName = pathMatcher.group(1);
            String requiredRole = "ROLE_INFOPACK" + infoPackName.toUpperCase();

            // Check if the authenticated user has the required role
            return authentication.getAuthorities().stream()
                    .anyMatch(authority -> authority.getAuthority().equals(requiredRole));
        }
        return false;
    }
}

Both approaches let you add new InfoPacks anytime—just register the corresponding role in your database, and the security rules will apply immediately without redeployment.


内容的提问来源于stack exchange,提问作者Scaddenp

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:43:05