如何将自定义注释中的参数传递给库中的 WebSecurityConfigurer
Posted
技术标签:
【中文标题】如何将自定义注释中的参数传递给库中的 WebSecurityConfigurer【英文标题】:How to pass parameters from custom annotation to WebSecurityConfigurer in library 【发布时间】: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 会有所帮助?不过,您的库可能更容易接受排除的路径作为配置属性,但 【参考方案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);
【讨论】:
以上是关于如何将自定义注释中的参数传递给库中的 WebSecurityConfigurer的主要内容,如果未能解决你的问题,请参考以下文章
将自定义参数传递给 Symfony2 中的自定义 ValidationConstraint