姓名: 李小娜
[嵌牛導(dǎo)讀]:這篇文章主要介紹了詳解spring security 配置多個(gè)AuthenticationProvider
[嵌牛鼻子]:spring security的大體介紹 ??開(kāi)始配置多AuthenticationProvider ?
[嵌牛提問(wèn)] :spring security 如何配置多個(gè)AuthenticationProvider冠跷?
[嵌牛正文] :spring security的大體介紹
spring security本身如果只是說(shuō)配置,還是很簡(jiǎn)單易懂的(我也不知道網(wǎng)上說(shuō)spring
security難寻咒,難在哪里)荣回,簡(jiǎn)單不需要特別的功能祭钉,一個(gè)WebSecurityConfigurerAdapter的實(shí)現(xiàn),然后實(shí)現(xiàn)UserServiceDetails就是簡(jiǎn)單的數(shù)據(jù)庫(kù)驗(yàn)證了,這個(gè)我就不說(shuō)了威恼。
spring security大體上是由一堆Filter(所以才能在spring
mvc前攔截請(qǐng)求)實(shí)現(xiàn)的,F(xiàn)ilter有幾個(gè)寝并,登出Filter(LogoutFilter)箫措,用戶(hù)名密碼驗(yàn)證Filter(UsernamePasswordAuthenticationFilter)之類(lèi)的,F(xiàn)ilter再交由其他組件完成細(xì)分的功能衬潦,例如最常用的UsernamePasswordAuthenticationFilter會(huì)持有一個(gè)AuthenticationManager引用斤蔓,AuthenticationManager顧名思義,驗(yàn)證管理器镀岛,負(fù)責(zé)驗(yàn)證的弦牡,但AuthenticationManager本身并不做具體的驗(yàn)證工作,AuthenticationManager持有一個(gè)AuthenticationProvider集合哎媚,AuthenticationProvider才是做驗(yàn)證工作的組件喇伯,AuthenticationManager和AuthenticationProvider的工作機(jī)制可以大概看一下這兩個(gè)的java
doc,然后成功失敗都有相對(duì)應(yīng)該Handler 拨与。大體的spring security的驗(yàn)證工作流程就是這樣了稻据。
開(kāi)始配置多AuthenticationProvider
首先,寫(xiě)一個(gè)內(nèi)存認(rèn)證的AuthenticationProvider,這里我簡(jiǎn)單地寫(xiě)一個(gè)只有root帳號(hào)的AuthenticationProvider
packagecom.scau.equipment.config.common.security.provider;
importorg.springframework.security.authentication.AuthenticationProvider;
importorg.springframework.security.authentication.UsernamePasswordAuthenticationToken;
importorg.springframework.security.core.Authentication;
importorg.springframework.security.core.AuthenticationException;
importorg.springframework.security.core.GrantedAuthority;
importorg.springframework.security.core.authority.SimpleGrantedAuthority;
importorg.springframework.security.core.userdetails.User;
importorg.springframework.stereotype.Component;
importjava.util.Arrays;
importjava.util.List;
/**
* Created by Administrator on 2017-05-10.
*/
@Component
publicclassInMemoryAuthenticationProviderimplementsAuthenticationProvider {
privatefinalString adminName ="root";
privatefinalString adminPassword ="root";
//根用戶(hù)擁有全部的權(quán)限
privatefinalList authorities = Arrays.asList(newSimpleGrantedAuthority("CAN_SEARCH"),
newSimpleGrantedAuthority("CAN_SEARCH"),
newSimpleGrantedAuthority("CAN_EXPORT"),
newSimpleGrantedAuthority("CAN_IMPORT"),
newSimpleGrantedAuthority("CAN_BORROW"),
newSimpleGrantedAuthority("CAN_RETURN"),
newSimpleGrantedAuthority("CAN_REPAIR"),
newSimpleGrantedAuthority("CAN_DISCARD"),
newSimpleGrantedAuthority("CAN_EMPOWERMENT"),
newSimpleGrantedAuthority("CAN_BREED"));
@Override
publicAuthentication authenticate(Authentication authentication)throwsAuthenticationException {
if(isMatch(authentication)){
User user =newUser(authentication.getName(),authentication.getCredentials().toString(),authorities);
returnnewUsernamePasswordAuthenticationToken(user,authentication.getCredentials(),authorities);
}
returnnull;
}
@Override
publicbooleansupports(Class authentication) {
returntrue;
}
privatebooleanisMatch(Authentication authentication){
if(authentication.getName().equals(adminName)&&authentication.getCredentials().equals(adminPassword))
returntrue;
else
returnfalse;
}
}
support方法檢查authentication的類(lèi)型是不是這個(gè)AuthenticationProvider支持的捻悯,這里我簡(jiǎn)單地返回true匆赃,就是所有都支持,這里所說(shuō)的authentication為什么會(huì)有多個(gè)類(lèi)型今缚,是因?yàn)槎鄠€(gè)AuthenticationProvider可以返回不同的Authentication算柳。
public Authentication authenticate(Authentication authentication) throws
AuthenticationException 方法就是驗(yàn)證過(guò)程。
如果AuthenticationProvider返回了null姓言,AuthenticationManager會(huì)交給下一個(gè)支持authentication類(lèi)型的AuthenticationProvider處理瞬项。
另外需要一個(gè)數(shù)據(jù)庫(kù)認(rèn)證的AuthenticationProvider,我們可以直接用spring
security提供的DaoAuthenticationProvider何荚,設(shè)置一下UserServiceDetails和PasswordEncoder就可以了
@Bean
DaoAuthenticationProvider daoAuthenticationProvider(){
DaoAuthenticationProvider daoAuthenticationProvider =newDaoAuthenticationProvider();
daoAuthenticationProvider.setPasswordEncoder(newBCryptPasswordEncoder());
daoAuthenticationProvider.setUserDetailsService(userServiceDetails);
returndaoAuthenticationProvider;
}
最后在WebSecurityConfigurerAdapter里配置一個(gè)含有以上兩個(gè)AuthenticationProvider的AuthenticationManager囱淋,依然重用spring
security提供的ProviderManager
packagecom.scau.equipment.config.common.security;
importcom.scau.equipment.config.common.security.handler.AjaxLoginFailureHandler;
importcom.scau.equipment.config.common.security.handler.AjaxLoginSuccessHandler;
importcom.scau.equipment.config.common.security.provider.InMemoryAuthenticationProvider;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.context.annotation.Bean;
importorg.springframework.context.annotation.Configuration;
importorg.springframework.security.authentication.AuthenticationManager;
importorg.springframework.security.authentication.ProviderManager;
importorg.springframework.security.authentication.dao.DaoAuthenticationProvider;
importorg.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
importorg.springframework.security.config.annotation.authentication.configurers.provisioning.InMemoryUserDetailsManagerConfigurer;
importorg.springframework.security.config.annotation.authentication.configurers.provisioning.UserDetailsManagerConfigurer;
importorg.springframework.security.config.annotation.web.builders.HttpSecurity;
importorg.springframework.security.config.annotation.web.builders.WebSecurity;
importorg.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
importorg.springframework.security.core.GrantedAuthority;
importorg.springframework.security.core.authority.SimpleGrantedAuthority;
importorg.springframework.security.core.userdetails.UserDetailsService;
importorg.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
importjava.util.Arrays;
importjava.util.List;
/**
* Created by Administrator on 2017/2/17.
*/
@Configuration
publicclassSecurityConfigextendsWebSecurityConfigurerAdapter {
@Autowired
UserDetailsService userServiceDetails;
@Autowired
InMemoryAuthenticationProvider inMemoryAuthenticationProvider;
@Bean
DaoAuthenticationProvider daoAuthenticationProvider(){
DaoAuthenticationProvider daoAuthenticationProvider =newDaoAuthenticationProvider();
daoAuthenticationProvider.setPasswordEncoder(newBCryptPasswordEncoder());
daoAuthenticationProvider.setUserDetailsService(userServiceDetails);
returndaoAuthenticationProvider;
}
@Override
protectedvoidconfigure(HttpSecurity http)throwsException {
http
.csrf().disable()
.rememberMe().alwaysRemember(true).tokenValiditySeconds(86400).and()
.authorizeRequests()
.antMatchers("/","/*swagger*/**","/v2/api-docs").permitAll()
.anyRequest().authenticated().and()
.formLogin()
.loginPage("/")
.loginProcessingUrl("/login")
.successHandler(newAjaxLoginSuccessHandler())
.failureHandler(newAjaxLoginFailureHandler()).and()
.logout().logoutUrl("/logout").logoutSuccessUrl("/");
}
@Override
publicvoidconfigure(WebSecurity web)throwsException {
web.ignoring().antMatchers("/public/**","/webjars/**","/v2/**","/swagger**");
}
@Override
protectedAuthenticationManager authenticationManager()throwsException {
ProviderManager authenticationManager =newProviderManager(Arrays.asList(inMemoryAuthenticationProvider,daoAuthenticationProvider()));
//不擦除認(rèn)證密碼,擦除會(huì)導(dǎo)致TokenBasedRememberMeServices因?yàn)檎也坏紺redentials再調(diào)用UserDetailsService而拋出UsernameNotFoundException
authenticationManager.setEraseCredentialsAfterAuthentication(false);
returnauthenticationManager;
}
/**
* 這里需要提供UserDetailsService的原因是RememberMeServices需要用到
*@return
*/
@Override
protectedUserDetailsService userDetailsService() {
returnuserServiceDetails;
}
}
基本上都是重用了原有的類(lèi)餐塘,很多都是默認(rèn)使用的妥衣,只不過(guò)為了修改下行為而重新配置。