spring security 配置多個AuthenticationProvider

前言

  發現不多關於spring security的文章,基本都是入門級的,配個UserServiceDetails或者配個路由控制就完事了,並且不少仍是xml配置,國內通病...so,本文裏的配置都是java配置,不涉及xml配置,事實上我也不會xml配置java

spring security的大致介紹

  spring security自己若是隻是說配置,仍是很簡單易懂的(我也不知道網上說spring security難,難在哪裏),簡單不須要特別的功能,一個WebSecurityConfigurerAdapter的實現,而後實現UserServiceDetails就是簡單的數據庫驗證了,這個我就不說了。web

  spring security大致上是由一堆Filter(因此才能在spring mvc前攔截請求)實現的,Filter有幾個,登出Filter(LogoutFilter),用戶名密碼驗證Filter(UsernamePasswordAuthenticationFilter)之類的,Filter再交由其餘組件完成細分的功能,例如最經常使用的UsernamePasswordAuthenticationFilter會持有一個AuthenticationManager引用,AuthenticationManager顧名思義,驗證管理器,負責驗證的,但AuthenticationManager自己並不作具體的驗證工做,AuthenticationManager持有一個AuthenticationProvider集合,AuthenticationProvider纔是作驗證工做的組件,AuthenticationManager和AuthenticationProvider的工做機制能夠大概看一下這兩個的java doc,而後成功失敗都有相對應該Handler 。大致的spring security的驗證工做流程就是這樣了。spring

開始配置多AuthenticationProvider

首先,寫一個內存認證的AuthenticationProvider,這裏我簡單地寫一個只有root賬號的AuthenticationProvider

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";

    //根用戶擁有所有的權限
    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;
    }
}
InMemoryAuthenticationProvider

  support方法檢查authentication的類型是否是這個AuthenticationProvider支持的,這裏我簡單地返回true,就是全部都支持,這裏所說的authentication爲何會有多個類型,是由於多個AuthenticationProvider能夠返回不一樣的Authentication。數據庫

  public Authentication authenticate(Authentication authentication) throws AuthenticationException 方法就是驗證過程。api

  若是AuthenticationProvider返回了null,AuthenticationManager會交給下一個支持authentication類型的AuthenticationProvider處理。mvc

 

另外須要一個數據庫認證的AuthenticationProvider,咱們能夠直接用spring security提供的DaoAuthenticationProvider,設置一下UserServiceDetails和PasswordEncoder就能夠了

 @Bean
    DaoAuthenticationProvider daoAuthenticationProvider(){
        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
        daoAuthenticationProvider.setPasswordEncoder(new BCryptPasswordEncoder());
        daoAuthenticationProvider.setUserDetailsService(userServiceDetails);
        return daoAuthenticationProvider;
    }
DaoAuthenticationProvider

 

最後在WebSecurityConfigurerAdapter裏配置一個含有以上兩個AuthenticationProvider的AuthenticationManager,依然重用spring security提供的ProviderManager

 1 package com.scau.equipment.config.common.security;
 2 
 3 import com.scau.equipment.config.common.security.handler.AjaxLoginFailureHandler;
 4 import com.scau.equipment.config.common.security.handler.AjaxLoginSuccessHandler;
 5 import com.scau.equipment.config.common.security.provider.InMemoryAuthenticationProvider;
 6 import org.springframework.beans.factory.annotation.Autowired;
 7 import org.springframework.context.annotation.Bean;
 8 import org.springframework.context.annotation.Configuration;
 9 import org.springframework.security.authentication.AuthenticationManager;
10 import org.springframework.security.authentication.ProviderManager;
11 import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
12 import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
13 import org.springframework.security.config.annotation.authentication.configurers.provisioning.InMemoryUserDetailsManagerConfigurer;
14 import org.springframework.security.config.annotation.authentication.configurers.provisioning.UserDetailsManagerConfigurer;
15 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
16 import org.springframework.security.config.annotation.web.builders.WebSecurity;
17 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
18 import org.springframework.security.core.GrantedAuthority;
19 import org.springframework.security.core.authority.SimpleGrantedAuthority;
20 import org.springframework.security.core.userdetails.UserDetailsService;
21 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
22 
23 import java.util.Arrays;
24 import java.util.List;
25 
26 /**
27  * Created by Administrator on 2017/2/17.
28  */
29 @Configuration
30 public class SecurityConfig extends WebSecurityConfigurerAdapter {
31 
32     @Autowired
33     UserDetailsService userServiceDetails;
34 
35     @Autowired
36     InMemoryAuthenticationProvider inMemoryAuthenticationProvider;
37 
38     @Bean
39     DaoAuthenticationProvider daoAuthenticationProvider(){
40         DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
41         daoAuthenticationProvider.setPasswordEncoder(new BCryptPasswordEncoder());
42         daoAuthenticationProvider.setUserDetailsService(userServiceDetails);
43         return daoAuthenticationProvider;
44     }
45 
46     @Override
47     protected void configure(HttpSecurity http) throws Exception {
48         http
49                 .csrf().disable()
50                 .rememberMe().alwaysRemember(true).tokenValiditySeconds(86400).and()
51                 .authorizeRequests()
52                     .antMatchers("/","/*swagger*/**", "/v2/api-docs").permitAll()
53                     .anyRequest().authenticated().and()
54                 .formLogin()
55                     .loginPage("/")
56                     .loginProcessingUrl("/login")
57                     .successHandler(new AjaxLoginSuccessHandler())
58                     .failureHandler(new AjaxLoginFailureHandler()).and()
59                 .logout().logoutUrl("/logout").logoutSuccessUrl("/");
60     }
61 
62     @Override
63     public void configure(WebSecurity web) throws Exception {
64         web.ignoring().antMatchers("/public/**", "/webjars/**", "/v2/**", "/swagger**");
65     }
66 
67     @Override
68     protected AuthenticationManager authenticationManager() throws Exception {
69         ProviderManager authenticationManager = new ProviderManager(Arrays.asList(inMemoryAuthenticationProvider,daoAuthenticationProvider()));
70         //不擦除認證密碼,擦除會致使TokenBasedRememberMeServices由於找不到Credentials再調用UserDetailsService而拋出UsernameNotFoundException
71         authenticationManager.setEraseCredentialsAfterAuthentication(false);
72         return authenticationManager;
73     }
74 
75     /**
76      * 這裏須要提供UserDetailsService的緣由是RememberMeServices須要用到
77      * @return
78      */
79     @Override
80     protected UserDetailsService userDetailsService() {
81         return userServiceDetails;
82     }
83 }
WebSecurityConfigurerAdapter

 

  基本上都是重用了原有的類,不少都是默認使用的,只不過爲了修改下行爲而從新配置。其實若是偷懶,直接用一個UserDetailsService,在裏面作各類認證也是能夠的~不過這樣就沒意思了ide

相關文章
相關標籤/搜索