前言
發(fā)現(xiàn)很少關(guān)于spring security的文章,基本都是入門級(jí)的,配個(gè)UserServiceDetails或者配個(gè)路由控制就完事了,而且很多還是xml配置,國(guó)內(nèi)通病...so,本文里的配置都是java配置,不涉及xml配置,事實(shí)上我也不會(huì)xml配置
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),用戶名密碼驗(yàn)證Filter(UsernamePasswordAuthenticationFilter)之類的,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
首先,寫一個(gè)內(nèi)存認(rèn)證的AuthenticationProvider,這里我簡(jiǎn)單地寫一個(gè)只有root帳號(hào)的AuthenticationProvider
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
package com.scau.equipment.config.common.security.provider; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.User; import org.springframework.stereotype.Component; import java.util.Arrays; import java.util.List; /** * Created by Administrator on 2017-05-10. */ @Component public class InMemoryAuthenticationProvider implements AuthenticationProvider { private final String adminName = "root" ; private final String adminPassword = "root" ; //根用戶擁有全部的權(quán)限 private final List<GrantedAuthority> authorities = Arrays.asList( new SimpleGrantedAuthority( "CAN_SEARCH" ), new SimpleGrantedAuthority( "CAN_SEARCH" ), new SimpleGrantedAuthority( "CAN_EXPORT" ), new SimpleGrantedAuthority( "CAN_IMPORT" ), new SimpleGrantedAuthority( "CAN_BORROW" ), new SimpleGrantedAuthority( "CAN_RETURN" ), new SimpleGrantedAuthority( "CAN_REPAIR" ), new SimpleGrantedAuthority( "CAN_DISCARD" ), new SimpleGrantedAuthority( "CAN_EMPOWERMENT" ), new SimpleGrantedAuthority( "CAN_BREED" )); @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { if (isMatch(authentication)){ User user = new User(authentication.getName(),authentication.getCredentials().toString(),authorities); return new UsernamePasswordAuthenticationToken(user,authentication.getCredentials(),authorities); } return null ; } @Override public boolean supports(Class<?> authentication) { return true ; } private boolean isMatch(Authentication authentication){ if (authentication.getName().equals(adminName)&&authentication.getCredentials().equals(adminPassword)) return true ; else return false ; } } |
support方法檢查authentication的類型是不是這個(gè)AuthenticationProvider支持的,這里我簡(jiǎn)單地返回true,就是所有都支持,這里所說(shuō)的authentication為什么會(huì)有多個(gè)類型,是因?yàn)槎鄠€(gè)AuthenticationProvider可以返回不同的Authentication。
public Authentication authenticate(Authentication authentication) throws AuthenticationException 方法就是驗(yàn)證過(guò)程。
如果AuthenticationProvider返回了null,AuthenticationManager會(huì)交給下一個(gè)支持authentication類型的AuthenticationProvider處理。
另外需要一個(gè)數(shù)據(jù)庫(kù)認(rèn)證的AuthenticationProvider,我們可以直接用spring security提供的DaoAuthenticationProvider,設(shè)置一下UserServiceDetails和PasswordEncoder就可以了
1
2
3
4
5
6
7
|
@Bean DaoAuthenticationProvider daoAuthenticationProvider(){ DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider(); daoAuthenticationProvider.setPasswordEncoder( new BCryptPasswordEncoder()); daoAuthenticationProvider.setUserDetailsService(userServiceDetails); return daoAuthenticationProvider; } |
最后在WebSecurityConfigurerAdapter里配置一個(gè)含有以上兩個(gè)AuthenticationProvider的AuthenticationManager,依然重用spring security提供的ProviderManager
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
package com.scau.equipment.config.common.security; import com.scau.equipment.config.common.security.handler.AjaxLoginFailureHandler; import com.scau.equipment.config.common.security.handler.AjaxLoginSuccessHandler; import com.scau.equipment.config.common.security.provider.InMemoryAuthenticationProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.ProviderManager; import org.springframework.security.authentication.dao.DaoAuthenticationProvider; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.authentication.configurers.provisioning.InMemoryUserDetailsManagerConfigurer; import org.springframework.security.config.annotation.authentication.configurers.provisioning.UserDetailsManagerConfigurer; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.WebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import java.util.Arrays; import java.util.List; /** * Created by Administrator on 2017/2/17. */ @Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired UserDetailsService userServiceDetails; @Autowired InMemoryAuthenticationProvider inMemoryAuthenticationProvider; @Bean DaoAuthenticationProvider daoAuthenticationProvider(){ DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider(); daoAuthenticationProvider.setPasswordEncoder( new BCryptPasswordEncoder()); daoAuthenticationProvider.setUserDetailsService(userServiceDetails); return daoAuthenticationProvider; } @Override protected void configure(HttpSecurity http) throws Exception { http .csrf().disable() .rememberMe().alwaysRemember( true ).tokenValiditySeconds( 86400 ).and() .authorizeRequests() .antMatchers( "/" , "/*swagger*/**" , "/v2/api-docs" ).permitAll() .anyRequest().authenticated().and() .formLogin() .loginPage( "/" ) .loginProcessingUrl( "/login" ) .successHandler( new AjaxLoginSuccessHandler()) .failureHandler( new AjaxLoginFailureHandler()).and() .logout().logoutUrl( "/logout" ).logoutSuccessUrl( "/" ); } @Override public void configure(WebSecurity web) throws Exception { web.ignoring().antMatchers( "/public/**" , "/webjars/**" , "/v2/**" , "/swagger**" ); } @Override protected AuthenticationManager authenticationManager() throws Exception { ProviderManager authenticationManager = new ProviderManager(Arrays.asList(inMemoryAuthenticationProvider,daoAuthenticationProvider())); //不擦除認(rèn)證密碼,擦除會(huì)導(dǎo)致TokenBasedRememberMeServices因?yàn)檎也坏紺redentials再調(diào)用UserDetailsService而拋出UsernameNotFoundException authenticationManager.setEraseCredentialsAfterAuthentication( false ); return authenticationManager; } /** * 這里需要提供UserDetailsService的原因是RememberMeServices需要用到 * @return */ @Override protected UserDetailsService userDetailsService() { return userServiceDetails; } } |
基本上都是重用了原有的類,很多都是默認(rèn)使用的,只不過(guò)為了修改下行為而重新配置。其實(shí)如果偷懶,直接用一個(gè)UserDetailsService,在里面做各種認(rèn)證也是可以的~不過(guò)這樣就沒(méi)意思了
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。
原文鏈接:http://www.cnblogs.com/scau-chm/p/6836748.html?utm_source=tuicool&utm_medium=referral