欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

SpringSecurity------WebSecurityConfigurerAdapter配置适配器类

程序员文章站 2022-06-28 07:59:37
SpringSecurity------WebSecurityConfigurerAdapter配置适配器一、属性一、属性...

一、属性

SpringSecurity------WebSecurityConfigurerAdapter配置适配器类

二、构造器

1、开启默认配置构建WebSecurityConfigurerAdapter

该种方式构建出来的配置不启用默认配置

protected WebSecurityConfigurerAdapter() {
	this(false);
}

2、指定是否开启默认配置构建WebSecurityConfigurerAdapter

protected WebSecurityConfigurerAdapter(boolean disableDefaults) {
	this.disableDefaults = disableDefaults;
}

三、WebSecurityConfigurerAdapter主要做了什么

四、几个内部类

1、UserDetailsServiceDelegator

使用此代理类的主要作用是保证UserDetailsService被成功创建后再调用他的loadUserByUsername()方法

通过以下程序逻辑保证在调用loadUserByUsername()方法时,UserDetailsService已被成功创建:
(1)构造这个类时需要传入一组AuthenticationManagerBuilder,设置到delegateBuilders属性
(2)在loadUserByUsername()方法中遍历delegateBuilders属性值,获取UserDetails的一个实例(第一个构建成功的UserDetails会被立即设置到delegate字段,然后结束遍历)
(3)调用delegate自身的loadUserByUsername()方法

static final class UserDetailsServiceDelegator implements UserDetailsService {
    //AuthenticationManager建造器
	private List<AuthenticationManagerBuilder> delegateBuilders;
    //实际执行loadUserByUsername()方法获取UserDetails的类
	private UserDetailsService delegate;
    //一个锁对象,用于控制同步方法
	private final Object delegateMonitor = new Object();
    
	UserDetailsServiceDelegator(List<AuthenticationManagerBuilder> delegateBuilders) {
		Assert.isTrue(!delegateBuilders.contains(null),
				() -> "delegateBuilders cannot contain null values. Got " + delegateBuilders);
		this.delegateBuilders = delegateBuilders;
	}

	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		if (this.delegate != null) {
			return this.delegate.loadUserByUsername(username);
		}
		synchronized (this.delegateMonitor) {
			if (this.delegate == null) {
				for (AuthenticationManagerBuilder delegateBuilder : this.delegateBuilders) {
					this.delegate = delegateBuilder.getDefaultUserDetailsService();
					if (this.delegate != null) {
						break;
					}
				}
				if (this.delegate == null) {
					throw new IllegalStateException("UserDetailsService is required.");
				}
				this.delegateBuilders = null;
			}
		}
		return this.delegate.loadUserByUsername(username);
	}
}

2、AuthenticationManagerDelegator

类似UserDetailsServiceDelegator的作用,保证通过AuthenticationManager获取Authentication时,AuthenticationManager是已经被创建成功的

static final class AuthenticationManagerDelegator implements AuthenticationManager {

	private AuthenticationManagerBuilder delegateBuilder;

	private AuthenticationManager delegate;

	private final Object delegateMonitor = new Object();

	private Set<String> beanNames;

	AuthenticationManagerDelegator(AuthenticationManagerBuilder delegateBuilder, ApplicationContext context) {
		Assert.notNull(delegateBuilder, "delegateBuilder cannot be null");
		Field parentAuthMgrField = ReflectionUtils.findField(AuthenticationManagerBuilder.class,
				"parentAuthenticationManager");
		ReflectionUtils.makeAccessible(parentAuthMgrField);
		this.beanNames = getAuthenticationManagerBeanNames(context);
		validateBeanCycle(ReflectionUtils.getField(parentAuthMgrField, delegateBuilder), this.beanNames);
		this.delegateBuilder = delegateBuilder;
	}

	@Override
	public Authentication authenticate(Authentication authentication) throws AuthenticationException {
		if (this.delegate != null) {
			return this.delegate.authenticate(authentication);
		}
		synchronized (this.delegateMonitor) {
			if (this.delegate == null) {
				this.delegate = this.delegateBuilder.getObject();
				this.delegateBuilder = null;
			}
		}
		return this.delegate.authenticate(authentication);
	}

	private static Set<String> getAuthenticationManagerBeanNames(ApplicationContext applicationContext) {
		String[] beanNamesForType = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext,
				AuthenticationManager.class);
		return new HashSet<>(Arrays.asList(beanNamesForType));
	}

	private static void validateBeanCycle(Object auth, Set<String> beanNames) {
		if (auth == null || beanNames.isEmpty() || !(auth instanceof Advised)) {
			return;
		}
		TargetSource targetSource = ((Advised) auth).getTargetSource();
		if (!(targetSource instanceof LazyInitTargetSource)) {
			return;
		}
		LazyInitTargetSource lits = (LazyInitTargetSource) targetSource;
		if (beanNames.contains(lits.getTargetBeanName())) {
			throw new FatalBeanException(
					"A dependency cycle was detected when trying to resolve the AuthenticationManager. "
							+ "Please ensure you have configured authentication.");
		}
	}
}

3、DefaultPasswordEncoderAuthenticationManagerBuilder

作用:拥有默认密码编码器的AuthenticationManager建造器

static class DefaultPasswordEncoderAuthenticationManagerBuilder extends AuthenticationManagerBuilder {

	private PasswordEncoder defaultPasswordEncoder;

		/**
		 * Creates a new instance
		 * @param objectPostProcessor the {@link ObjectPostProcessor} instance to use.
		 */
	DefaultPasswordEncoderAuthenticationManagerBuilder(ObjectPostProcessor<Object> objectPostProcessor,
			PasswordEncoder defaultPasswordEncoder) {
		super(objectPostProcessor);
		this.defaultPasswordEncoder = defaultPasswordEncoder;
	}

	@Override
	public InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder> inMemoryAuthentication()
			throws Exception {
		return super.inMemoryAuthentication().passwordEncoder(this.defaultPasswordEncoder);
	}

	@Override
	public JdbcUserDetailsManagerConfigurer<AuthenticationManagerBuilder> jdbcAuthentication() throws Exception {
		return super.jdbcAuthentication().passwordEncoder(this.defaultPasswordEncoder);
	}

	@Override
	public <T extends UserDetailsService> DaoAuthenticationConfigurer<AuthenticationManagerBuilder, T> userDetailsService(
			T userDetailsService) throws Exception {
		return super.userDetailsService(userDetailsService).passwordEncoder(this.defaultPasswordEncoder);
	}
}

4、LazyPasswordEncoder

作用:懒加载的密码编码器

该类的核心逻辑在getPasswordEncoder()方法,他首先会从容器中获取PasswordEncoder,如果没有获取到,则使用PasswordEncoderFactories创建一个PasswordEncoder(DelegatingPasswordEncoder)

static class LazyPasswordEncoder implements PasswordEncoder {

	private ApplicationContext applicationContext;

	private PasswordEncoder passwordEncoder;

	LazyPasswordEncoder(ApplicationContext applicationContext) {
		this.applicationContext = applicationContext;
	}

	@Override
	public String encode(CharSequence rawPassword) {
		return getPasswordEncoder().encode(rawPassword);
	}

	@Override
	public boolean matches(CharSequence rawPassword, String encodedPassword) {
		return getPasswordEncoder().matches(rawPassword, encodedPassword);
	}

	@Override
	public boolean upgradeEncoding(String encodedPassword) {
		return getPasswordEncoder().upgradeEncoding(encodedPassword);
	}
	
	private PasswordEncoder getPasswordEncoder() {
		if (this.passwordEncoder != null) {
			return this.passwordEncoder;
		}
		PasswordEncoder passwordEncoder = getBeanOrNull(PasswordEncoder.class);
		if (passwordEncoder == null) {
			passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
		}
		this.passwordEncoder = passwordEncoder;
		return passwordEncoder;
	}
    //从ApplicationContext中获取PasswordEncoder的实现,没有获取到就返回空
	private <T> T getBeanOrNull(Class<T> type) {
		try {
			return this.applicationContext.getBean(type);
		}
		catch (NoSuchBeanDefinitionException ex) {
			return null;
		}
	}

	@Override
	public String toString() {
		return getPasswordEncoder().toString();
	}
}

五、依赖注入的方法(Spring构建过程中会触发这些方法执行)

1、引入ApplicationContext

这个方法是当前配置适配器的核心方法,从依赖注入的ApplicationContext对象中获取所需的实例对象,然后创建了两个AuthenticationManagerBuilder赋值给当前配置类的两个属性字段。

@Autowired
public void setApplicationContext(ApplicationContext context) {
    //注入ApplicationContext 
	this.context = context;
	//获取容器中唯一的一个ObjectPostProcessor实例:AutowireBeanFactoryObjectPostProcessor
	ObjectPostProcessor<Object> objectPostProcessor = context.getBean(ObjectPostProcessor.class);
	//创建一个懒加载的LazyPasswordEncoder实例,这个类是本类的一个内部类
	LazyPasswordEncoder passwordEncoder = new LazyPasswordEncoder(context);
	//创建一个默认的AuthenticationManagerBuilder,这个类是当前配置类的一个内部类
	this.authenticationBuilder = new DefaultPasswordEncoderAuthenticationManagerBuilder(objectPostProcessor,
			passwordEncoder);
	//创建一个本地配置的AuthenticationManagerBuilder,重写了eraseCredentials()和authenticationEventPublisher()方法
	//使用当前配置类中的authenticationBuilder擦除认证凭证和发布事件
	this.localConfigureAuthenticationBldr = new DefaultPasswordEncoderAuthenticationManagerBuilder(
			objectPostProcessor, passwordEncoder) {

		@Override
		public AuthenticationManagerBuilder eraseCredentials(boolean eraseCredentials) {
			WebSecurityConfigurerAdapter.this.authenticationBuilder.eraseCredentials(eraseCredentials);
			return super.eraseCredentials(eraseCredentials);
		}

		@Override
		public AuthenticationManagerBuilder authenticationEventPublisher(
				AuthenticationEventPublisher eventPublisher) {
			WebSecurityConfigurerAdapter.this.authenticationBuilder.authenticationEventPublisher(eventPublisher);
			return super.authenticationEventPublisher(eventPublisher);
		}
	};
}

2、引入AuthenticationConfigurationObjectPostProcessor

@Autowired
public void setObjectPostProcessor(ObjectPostProcessor<Object> objectPostProcessor) {
	this.objectPostProcessor = objectPostProcessor;
}
@Autowired
public void setAuthenticationConfiguration(AuthenticationConfiguration authenticationConfiguration) {
	this.authenticationConfiguration = authenticationConfiguration;
}

3、引入ContentNegotiationStrategy和AuthenticationTrustResolver

@Autowired(required = false)
public void setContentNegotationStrategy(ContentNegotiationStrategy contentNegotiationStrategy) {
	this.contentNegotiationStrategy = contentNegotiationStrategy;
}
@Autowired(required = false)
public void setTrustResolver(AuthenticationTrustResolver trustResolver) {
	this.trustResolver = trustResolver;
}

六、初始化方法

在这个方法中,首先获取HttpSecurity,这个对象包含了用户的自定义配置信息,然后将这个HttpSecurity对象存入WebSecurity中,然后创建一个Runnable线程,这个线程用来初始化WebSecurity的FilterSecurityInterceptor

@Override
public void init(WebSecurity web) throws Exception {
	HttpSecurity http = getHttp();
	web.addSecurityFilterChainBuilder(http).postBuildAction(() -> {
		FilterSecurityInterceptor securityInterceptor = http.getSharedObject(FilterSecurityInterceptor.class);
		web.securityInterceptor(securityInterceptor);
	});
}

这个方法是用来获取HttpSecurity实例的,同时给localConfigureAuthenticationBldr添加一个事件发布器,给authenticationBuilder添加一个父级AuthenticationManager

@SuppressWarnings({ "rawtypes", "unchecked" })
protected final HttpSecurity getHttp() throws Exception {
	if (this.http != null) {
		return this.http;
	}
	AuthenticationEventPublisher eventPublisher = getAuthenticationEventPublisher();
	this.localConfigureAuthenticationBldr.authenticationEventPublisher(eventPublisher);
	AuthenticationManager authenticationManager = authenticationManager();
	this.authenticationBuilder.parentAuthenticationManager(authenticationManager);
	Map<Class<?>, Object> sharedObjects = createSharedObjects();
	this.http = new HttpSecurity(this.objectPostProcessor, this.authenticationBuilder, sharedObjects);
	if (!this.disableDefaults) {
		applyDefaultConfiguration(this.http);
		ClassLoader classLoader = this.context.getClassLoader();
		List<AbstractHttpConfigurer> defaultHttpConfigurers = SpringFactoriesLoader
				.loadFactories(AbstractHttpConfigurer.class, classLoader);
		for (AbstractHttpConfigurer configurer : defaultHttpConfigurers) {
			this.http.apply(configurer);
		}
	}
	//这是一个可供子类实现的钩子方法,子类重写这个方法提供自定义配置
	configure(this.http);
	return this.http;
}

获取一个事件发布器

private AuthenticationEventPublisher getAuthenticationEventPublisher() {
	if (this.context.getBeanNamesForType(AuthenticationEventPublisher.class).length > 0) {
		return this.context.getBean(AuthenticationEventPublisher.class);
	}
	return this.objectPostProcessor.postProcess(new DefaultAuthenticationEventPublisher());
}

获取一个AuthenticationManager

protected AuthenticationManager authenticationManager() throws Exception {
	if (!this.authenticationManagerInitialized) {
		configure(this.localConfigureAuthenticationBldr);
		if (this.disableLocalConfigureAuthenticationBldr) {
			this.authenticationManager = this.authenticationConfiguration.getAuthenticationManager();
		}
		else {
			this.authenticationManager = this.localConfigureAuthenticationBldr.build();
		}
		this.authenticationManagerInitialized = true;
	}
	return this.authenticationManager;
}

创建一些共享对象

private Map<Class<?>, Object> createSharedObjects() {
	Map<Class<?>, Object> sharedObjects = new HashMap<>();
	sharedObjects.putAll(this.localConfigureAuthenticationBldr.getSharedObjects());
	sharedObjects.put(UserDetailsService.class, userDetailsService());
	sharedObjects.put(ApplicationContext.class, this.context);
	sharedObjects.put(ContentNegotiationStrategy.class, this.contentNegotiationStrategy);
	sharedObjects.put(AuthenticationTrustResolver.class, this.trustResolver);
	return sharedObjects;
}

默认的配置

private void applyDefaultConfiguration(HttpSecurity http) throws Exception {
	http.csrf();
	http.addFilter(new WebAsyncManagerIntegrationFilter());
	http.exceptionHandling();
	http.headers();
	http.sessionManagement();
	http.securityContext();
	http.requestCache();
	http.anonymous();
	http.servletApi();
	http.apply(new DefaultLoginPageConfigurer<>());
	http.logout();
}

七、配置入口方法

这是一个模板方法,可以由子类实现,然后提供自定义的配置

protected void configure(HttpSecurity http) throws Exception {
	this.logger.debug("Using default configure(HttpSecurity). "
			+ "If subclassed this will potentially override subclass configure(HttpSecurity).");
	http.authorizeRequests((requests) -> requests.anyRequest().authenticated());
	http.formLogin();
	http.httpBasic();
}

这是一个钩子方法,使用该配置类的实例会调用该方法,所以这里我们可以自定义修改一些WebSecurity配置

@Override
public void configure(WebSecurity web) throws Exception {
}

这是一个模板方法,可以由子类实现,然后提供自定义的配置

protected void configure(AuthenticationManagerBuilder auth) throws Exception {
	this.disableLocalConfigureAuthenticationBldr = true;
}

八、配置入口方法

protected UserDetailsService userDetailsService() {
	AuthenticationManagerBuilder globalAuthBuilder = this.context.getBean(AuthenticationManagerBuilder.class);
	return new UserDetailsServiceDelegator(Arrays.asList(this.localConfigureAuthenticationBldr, globalAuthBuilder));
}
public UserDetailsService userDetailsServiceBean() throws Exception {
	AuthenticationManagerBuilder globalAuthBuilder = this.context.getBean(AuthenticationManagerBuilder.class);
	return new UserDetailsServiceDelegator(Arrays.asList(this.localConfigureAuthenticationBldr, globalAuthBuilder));
}
public AuthenticationManager authenticationManagerBean() throws Exception {
	return new AuthenticationManagerDelegator(this.authenticationBuilder, this.context);
}
protected final ApplicationContext getApplicationContext() {
	return this.context;
}

本文地址:https://blog.csdn.net/sanjun333/article/details/111397756

相关标签: SpringSecurity