SpringBoot中SpringSecurity Method Security创建原理分析

Method Security

如何使用

@EnableGlobalMethodSecurity(jsr250Enabled = true)
@Configuration
public class EunomiaSecurityConfig extends GlobalMethodSecurityConfiguration {
}

注意这里需要添加注解 @EnableGlobalMethodSecurity

如果需要拓展 GlobalMethodSecurityConfiguration,则继承该类。否则,使用默认配置。

原理

注解 @EnableGlobalMethodSecurity  导入了 GlobalMethodSecuritySelector.class,这个类特别关键。

@Import({ GlobalMethodSecuritySelector.class })
@EnableGlobalMethodSecurity
@Configuration
public @interface EnableGlobalMethodSecurity {
GlobalMethodSecuritySelector
final class GlobalMethodSecuritySelector implements ImportSelector {

	public final String[] selectImports(AnnotationMetadata importingClassMetadata) {
		Class<EnableGlobalMethodSecurity> annoType = EnableGlobalMethodSecurity.class;
		Map<String, Object> annotationAttributes = importingClassMetadata
				.getAnnotationAttributes(annoType.getName(), false);
		AnnotationAttributes attributes = AnnotationAttributes
				.fromMap(annotationAttributes);
	
		Class<?> importingClass = ClassUtils
				.resolveClassName(importingClassMetadata.getClassName(),
						ClassUtils.getDefaultClassLoader());
		boolean skipMethodSecurityConfiguration = GlobalMethodSecurityConfiguration.class
				.isAssignableFrom(importingClass);

		AdviceMode mode = attributes.getEnum("mode");
		boolean isProxy = AdviceMode.PROXY == mode;
		String autoProxyClassName = isProxy ? AutoProxyRegistrar.class
				.getName() : GlobalMethodSecurityAspectJAutoProxyRegistrar.class
				.getName();

		boolean jsr250Enabled = attributes.getBoolean("jsr250Enabled");

		List<String> classNames = new ArrayList<String>(4);
		if(isProxy) {
			classNames.add(MethodSecurityMetadataSourceAdvisorRegistrar.class.getName());
		}

		classNames.add(autoProxyClassName);

		if (!skipMethodSecurityConfiguration) {
			classNames.add(GlobalMethodSecurityConfiguration.class.getName());
		}

		if (jsr250Enabled) {
			classNames.add(Jsr250MetadataSourceConfiguration.class.getName());
		}

		return classNames.toArray(new String[0]);
	}
}

这个类会根据用户的应用配置类和它添加的 @EnableGlobalMethodSecurity 注解的属性值,返回需要import的类名。

这里我们以之前的配置类:EunomiaSecurityConfig位例,此时该方法会添加的类有:

  1. AutoProxyRegistrar
  2. MethodSecurityMetadataSourceAdvisorRegistrar
  3. EunomiaSecurityConfig
  4. Jsr250MetadataSourceConfiguration
非常关键一个类

MethodSecurityMetadataSourceAdvisorRegistrar

class MethodSecurityMetadataSourceAdvisorRegistrar implements
		ImportBeanDefinitionRegistrar {

	/**
	 * Register, escalate, and configure the AspectJ auto proxy creator based on the value
	 * of the @{@link EnableGlobalMethodSecurity#proxyTargetClass()} attribute on the
	 * importing {@code @Configuration} class.
	 */
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
			BeanDefinitionRegistry registry) {

		BeanDefinitionBuilder advisor = BeanDefinitionBuilder
				.rootBeanDefinition(MethodSecurityMetadataSourceAdvisor.class);
		advisor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
		advisor.addConstructorArgValue("methodSecurityInterceptor");
		advisor.addConstructorArgReference("methodSecurityMetadataSource");
		advisor.addConstructorArgValue("methodSecurityMetadataSource");

		MultiValueMap<String,Object> attributes = importingClassMetadata.getAllAnnotationAttributes(EnableGlobalMethodSecurity.class.getName());
		Integer order = (Integer) attributes.getFirst("order");
		if(order != null) {
			advisor.addPropertyValue("order", order);
		}

		registry.registerBeanDefinition("metaDataSourceAdvisor",
				advisor.getBeanDefinition());
	}
}

这里会手动注册一个Advisor: MethodSecurityMetadataSourceAdvisor

MethodSecurityMetadataSourceAdvisor的 beanName指向的就是GlobalMethodSecurityConfiguration#methodSecurityInterceptor

即最后使用了methodSecurityInterceptor这个bean。

疑问

到这里你可能会想问那ImportSelector#selectImports什么时候被调用?

具体请参考 ImportSelector

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值