【问题标题】:How to pass parameters from custom annotation to WebSecurityConfigurer in library如何将自定义注释中的参数传递给库中的 WebSecurityConfigurer
【发布时间】:2021-08-08 20:45:33
【问题描述】:

您好,我们正在构建自定义 Spring 安全库

我们需要将 {"/v1","/v2"} 路径通过主项目中存在的 @EnableMySpringSecurity(excludePaths = {"/v1","/v2"}) 传递到库 websecurity,以便我们可以从安全性中忽略这些端点

@EnableMySpringSecurity(excludePaths = {"/v1","/v2"})
@EnableWebMvc
public class WebAppConfiguration extends BaseWebAppConfiguration {

来自自定义 JAR 的网络安全配置

@EnableWebSecurity(debug = true)
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public static class SecurityConfig extends WebSecurityConfigurerAdapter {

@Override
public void configure(WebSecurity web){
 web.ignoring().antMatchers(excludePaths );

如何将从@EnableMYSpringSecurity 传递的值传递给webSecuirty web.ignoring.antMatchers

我们的注解配置

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface EnableMySpringSecurity {
    String[] excludePaths() default {};
}

我试过 ApplicationStartupListener 但问题是,它是在 websecuirty 配置后初始化的

public class ApplicationStartupListener implements
        ApplicationListener<ContextRefreshedEvent> {

    private ApplicationContext context;

    private EnableMySSAnnotationProcessor processor;

    public ApplicationStartupListener(ApplicationContext context,
                                      EnableMySSAnnotationProcessor processor) {
        this.context = context;
        this.processor = processor;
    }

    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        Optional<EnableMySpringSecurity> annotation =
                context.getBeansWithAnnotation(EnableMySpringSecurity.class).keySet().stream()
                        .map(key -> context.findAnnotationOnBean(key, EnableMySpringSecurity.class))
                        .findFirst();
        annotation.ifPresent(enableMySpringSecurity-> processor.process(enableMySpringSecurity));
    }
}

【问题讨论】:

  • 也许this 会有所帮助?不过,您的库可能更容易接受排除的路径作为配置属性,但

标签: spring-boot spring-security spring-annotations websecurity


【解决方案1】:

一种方法是使用@Import 注释:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(MyWebSecurityConfiguration.class)
@EnableWebSecurity
public @interface EnableMyWebSecurity {
    String[] paths() default [];
}

然后是ImportAware接口:

@Configuration
public class MyWebSecurityConfiguration implements ImportAware {
    private String[] paths;

    @Bean
    WebSecurityCustomizer paths() {
        return (web) -> web.ignoring().antMatchers(paths);
    }

    @Override
    public void setImportMetadata(AnnotationMetadata importMetadata) {
        EnableMyWebSecurity annotation = importMetadata
            .getAnnotations().get(EnableMyWebSecurity.class).synthesize();
        this.paths = annotations.paths();
    }

}

请注意,顺便说一下,当您排除路径时,Spring Security 无法将安全标头添加为响应的一部分。如果您希望这些端点受 Spring Security 保护,但是是公共的,那么请考虑:

@Configuration
public class MyWebSecurityConfiguration implements ImportAware {
    private String[] paths;

    @Bean
    @Order(1)
    SecurityFilterChain paths(HttpSecurity http) {
        http
            .requestMatchers((requests) -> requests.antMatchers(paths))
            .authorizeRequests((authorize) -> authorize
                .anyRequest().permitAll()
            );
        return http.build();
    }

    @Override
    public void setImportMetadata(AnnotationMetadata importMetadata) {
        EnableMyWebSecurity annotation = importMetadata
            .getAnnotations().get(EnableMyWebSecurity.class).synthesize();
        this.paths = annotations.paths();
    }

}

第二种方法的好处是 Spring Security 不需要身份验证,但会添加安全响应标头。

【讨论】:

    【解决方案2】:

    @jzheaux 提供的解决方案有效

    还有另一种解决方案 - 是使用应用程序上下文 getBeansWithAnnoation

    @EnableWebSecurity(debug = true)
    @Configuration
    @Order(2147483640)
    @EnableGlobalMethodSecurity(prePostEnabled = true)
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
    
    @Autowired
    private ApplicationContext appContext;
    
     @Override
        public void configure(WebSecurity web){
            Map<String,Object> beanMap = this.appContext.getBeansWithAnnotation(EnableMYSpringSecurity.class);
    
            if(!beanMap.isEmpty()){
                EnableMYSpringSecurityanno = (EnableMYSpringSecurity) this.appContext.findAnnotationOnBean(beanMap.keySet()
                        .iterator()
                        .next(),EnableMYSpringSecurity.class);
    
                String[] permitPaths = anno.excludePaths();
                Arrays.stream(permitPaths).forEach(System.out::println);
    
            }
    

    【讨论】:

      猜你喜欢
      • 2022-11-25
      • 2014-12-10
      • 2021-12-06
      • 1970-01-01
      • 2022-06-20
      • 1970-01-01
      • 1970-01-01
      • 2013-03-15
      • 1970-01-01
      相关资源
      最近更新 更多