AuthenticationManagerBuilder
public class AuthenticationManagerBuilder
extends
AbstractConfiguredSecurityBuilder<AuthenticationManager, AuthenticationManagerBuilder>
implements ProviderManagerBuilder<AuthenticationManagerBuilder> {
private final Log logger = LogFactory.getLog(getClass());
private AuthenticationManager parentAuthenticationManager;
private List<AuthenticationProvider> authenticationProviders = new ArrayList<>();
private UserDetailsService defaultUserDetailsService;
private Boolean eraseCredentials;
private AuthenticationEventPublisher eventPublisher;
}
AuthenticationManagerBuilder用于创建AuthenticationManager。 允许轻松构建内存身份验证,LDAP身份验证,基于JDBC的身份验证,添加UserDetailsService以及添加AuthenticationProvider。
public interface SecurityBuilder<O> {
/**
* Builds the object and returns it or null.
*
* @return the Object to be built or null if the implementation allows it.
* @throws Exception if an error occurred when building the Object
*/
O build() throws Exception;
}
ProviderManagerBuilder扩展了SecurityBuilder接口增加了一个方法并且限制了build()方法只能创建AuthenticationManager类型的对象。
public interface ProviderManagerBuilder<B extends ProviderManagerBuilder<B>> extends
SecurityBuilder<AuthenticationManager> {
/**
* Add authentication based upon the custom {@link AuthenticationProvider} that is
* passed in. Since the {@link AuthenticationProvider} implementation is unknown, all
* customizations must be done externally and the {@link ProviderManagerBuilder} is
* returned immediately.
*
* Note that an Exception is thrown if an error occurs when adding the {@link AuthenticationProvider}.
*
* @return a {@link ProviderManagerBuilder} to allow further authentication to be
* provided to the {@link ProviderManagerBuilder}
*/
B authenticationProvider(AuthenticationProvider authenticationProvider);
}
authenticationProvider()方法在AuthenticationManagerBuilder中实现了,向AuthenticationProvider链表添加authenticationProvider。
public AuthenticationManagerBuilder authenticationProvider(
AuthenticationProvider authenticationProvider) {
this.authenticationProviders.add(authenticationProvider);
return this;
}
https://blog.csdn.net/shenchaohao12321/article/details/87721655
AbstractSecurityBuilder
public abstract class AbstractSecurityBuilder<O> implements SecurityBuilder<O> {
private AtomicBoolean building = new AtomicBoolean();
private O object;
/*
* (non-Javadoc)
*
* @see org.springframework.security.config.annotation.SecurityBuilder#build()
*/
public final O build() throws Exception {
if (this.building.compareAndSet(false, true)) {
this.object = doBuild();
return this.object;
}
throw new AlreadyBuiltException("This object has already been built");
}
/**
* Gets the object that was built. If it has not been built yet an Exception is
* thrown.
*
* @return the Object that was built
*/
public final O getObject() {
if (!this.building.get()) {
throw new IllegalStateException("This object has not been built");
}
return this.object;
}
/**
* Subclasses should implement this to perform the build.
*
* @return the object that should be returned by {@link #build()}.
*
* @throws Exception if an error occurs
*/
protected abstract O doBuild() throws Exception;
}
一个基础SecurityBuilder实现类,它确保构建的对象只构建一次。
AbstractConfiguredSecurityBuilder
public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBuilder<O>>
extends AbstractSecurityBuilder<O> {
private final Log logger = LogFactory.getLog(getClass());
private final LinkedHashMap<Class<? extends SecurityConfigurer<O, B>>, List<SecurityConfigurer<O, B>>> configurers = new LinkedHashMap<>();
private final List<SecurityConfigurer<O, B>> configurersAddedInInitializing = new ArrayList<>();
private final Map<Class<?>, Object> sharedObjects = new HashMap<>();
private final boolean allowConfigurersOfSameType;
private BuildState buildState = BuildState.UNBUILT;
private ObjectPostProcessor<Object> objectPostProcessor;
/***
* Creates a new instance with the provided {@link ObjectPostProcessor}. This post
* processor must support Object since there are many types of objects that may be
* post processed.
*
* @param objectPostProcessor the {@link ObjectPostProcessor} to use
*/
protected AbstractConfiguredSecurityBuilder(
ObjectPostProcessor<Object> objectPostProcessor) {
this(objectPostProcessor, false);
}
/***
* Creates a new instance with the provided {@link ObjectPostProcessor}. This post
* processor must support Object since there are many types of objects that may be
* post processed.
*
* @param objectPostProcessor the {@link ObjectPostProcessor} to use
* @param allowConfigurersOfSameType if true, will not override other
* {@link SecurityConfigurer}'s when performing apply
*/
protected AbstractConfiguredSecurityBuilder(
ObjectPostProcessor<Object> objectPostProcessor,
boolean allowConfigurersOfSameType) {
Assert.notNull(objectPostProcessor, "objectPostProcessor cannot be null");
this.objectPostProcessor = objectPostProcessor;
this.allowConfigurersOfSameType = allowConfigurersOfSameType;
}
}
一个基本的SecurityBuilder,允许将SecurityConfigurer应用于它。 这使得修改SecurityBuilder的策略可以自定义并分解为许多SecurityConfigurer对象,这些对象具有比SecurityBuilder更具体的目标。
例如,SecurityBuilder可以构建DelegatingFilterProxy,但SecurityConfigurer可能会使用会话管理,基于表单的登录,授权等所需的过滤器填充SecurityBuilder。
AbstractConfiguredSecurityBuilder有两个apply()方法,将SecurityConfigurerAdapter或SecurityConfigurer应用于此SecurityBuilder并调用SecurityConfigurerAdapter #setBuilder(SecurityBuilder)方法。
public <C extends SecurityConfigurerAdapter<O, B>> C apply(C configurer)
throws Exception {
configurer.addObjectPostProcessor(objectPostProcessor);
configurer.setBuilder((B) this);
add(configurer);
return configurer;
}
public <C extends SecurityConfigurer<O, B>> C apply(C configurer) throws Exception {
add(configurer);
return configurer;
}
这些通过apply()方法保存的SecurityConfigurer会在执行构建方法doBuild()中调用init()和configure()方法中执行。
private void init() throws Exception {
Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();
for (SecurityConfigurer<O, B> configurer : configurers) {
configurer.init((B) this);
}
for (SecurityConfigurer<O, B> configurer : configurersAddedInInitializing) {
configurer.init((B) this);
}
}
private void configure() throws Exception {
Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();
for (SecurityConfigurer<O, B> configurer : configurers) {
configurer.configure((B) this);
}
}
在doBuild()方法中最后一步是调用performBuild()方法用于执行构建,需要由子类去实现。
@Override
protected final O doBuild() throws Exception {
synchronized (configurers) {
buildState = BuildState.INITIALIZING;
beforeInit();
init();
buildState = BuildState.CONFIGURING;
beforeConfigure();
configure();
buildState = BuildState.BUILDING;
O result = performBuild();
buildState = BuildState.BUILT;
return result;
}
}
AuthenticationProvider
是此类的内部成员变量
认证是由 AuthenticationManager 来管理的,但是真正进行认证的是 AuthenticationManager 中定义的 AuthenticationProvider。AuthenticationManager 中可以定义有多个 AuthenticationProvider。当我们使用 authentication-provider 元素来定义一个 AuthenticationProvider 时,如果没有指定对应关联的 AuthenticationProvider 对象,Spring Security 默认会使用 DaoAuthenticationProvider。DaoAuthenticationProvider 在进行认证的时候需要一个 UserDetailsService 来获取用户的信息 UserDetails,其中包括用户名、密码和所拥有的权限等。所以如果我们需要改变认证的方式,我们可以实现自己的 AuthenticationProvider;如果需要改变认证的用户信息来源,我们可以实现 UserDetailsService。
AuthenticationManager 认证管理器
Spring Security中,接口AuthenticationManager用于抽象建模认证管理器,用于处理一个认证请求,也就是Spring Security中的Authentication认证令牌。
public interface AuthenticationManager {
// ~ Methods
// ========================================================================================================
Authentication authenticate(Authentication authentication)
throws AuthenticationException;
}
AuthenticationManager接口只定义了一个方法。
该方法接收一个认证令牌对象,也就是认证请求作为参数,如果其中的信息匹配到目标账号,则该方法返回同一个认证令牌对象,不过其中被认证过程填充了更多的账号信息,比如授权和用户详情等。
AuthenticationManager在认证过程中必须按以下顺序处理以下认证异常AuthenticationException :
DisabledException – 账号被禁用时抛出
LockedException – 账号被锁定时抛出
BadCredentialsException – 密码错误时抛出
Spring Security框架提供了AuthenticationManager的缺省实现ProviderManager。ProviderManager管理了多个身份管理源,或者叫做认证提供者AuthenticationProvider,用于认证用户。它自身不实现身份验证,而是逐一使用认证提供者进行认证,直到某一个认证提供者能够成功地验证该用户的身份(或者是已经尝试完了该集合中所有的认证提供者仍然不能认证该用户的身份)。通过ProviderManager,Spring Security能够为单个应用程序提供多种认证机制。
内部方法
userDetailsService
public <T extends UserDetailsService> DaoAuthenticationConfigurer<AuthenticationManagerBuilder, T> userDetailsService(
T userDetailsService) throws Exception {
this.defaultUserDetailsService = userDetailsService;
return apply(new DaoAuthenticationConfigurer<>(
userDetailsService));
}
基于传入的自定义UserDetailsService添加身份验证。然后它返回一个DaoAuthenticationConfigurer来允许自定义身份验证。此方法还确保UserDetailsService对getDefaultUserDetailsService方法可用。注意,其他的UserDetailsService可能覆盖这个UserDetailsService。
inMemoryAuthentication
public InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder> inMemoryAuthentication()
throws Exception {
return apply(new InMemoryUserDetailsManagerConfigurer<>());
}
将内存中身份验证添加到AuthenticationManagerBuilder中,并返回一个InMemoryUserDetailsManagerConfigurer,以允许对内存中身份验证进行定制。
isConfigured
public boolean isConfigured() {
return !authenticationProviders.isEmpty() || parentAuthenticationManager != null;
}
确定AuthenticationManagerBuilder是否配置为构建非空的AuthenticationManager。这意味着要么指定了一个非空父类,要么至少指定了一个AuthenticationProvider。
authenticationProvider
public AuthenticationManagerBuilder authenticationProvider(
AuthenticationProvider authenticationProvider) {
this.authenticationProviders.add(authenticationProvider);
return this;
}
基于传入的自定义AuthenticationProvider添加身份验证。因为AuthenticationProvider的实现是未知的,所以所有的定制都必须在外部完成,并且AuthenticationManagerBuilder会立即返回。注意,此方法不确保UserDetailsService对getDefaultUserDetailsService方法可用
eraseCredentials
public AuthenticationManagerBuilder eraseCredentials(boolean eraseCredentials) {
this.eraseCredentials = eraseCredentials;
return this;
}
AuthenticationManager是否应该在验证后擦除凭证
jdbcAuthentication
public JdbcUserDetailsManagerConfigurer<AuthenticationManagerBuilder> jdbcAuthentication()
throws Exception {
return apply(new JdbcUserDetailsManagerConfigurer<>());
}
在AuthenticationManagerBuilder增加数据库验证方式,如:
import javax.sql.DataSource;
@Autowired
private DataSource dataSource;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication()
.dataSource(dataSource)
.usersByUsernameQuery("select username,password,enabled from users WHERE username=?")
.authoritiesByUsernameQuery("select username,authority from authorities where username=?")
.passwordEncoder(new BCryptPasswordEncoder());//一定要使用加密,不加密它识别不了
}
设置的权限前缀放入数据库一定要加ROLE_,不然不会生效