• spring security 配置多个AuthenticationProvider


    前言

      发现很少关于spring security的文章,基本都是入门级的,配个UserServiceDetails或者配个路由控制就完事了,而且很多还是xml配置,国内通病...so,本文里的配置都是java配置,不涉及xml配置,事实上我也不会xml配置

    spring security的大体介绍

      spring security本身如果只是说配置,还是很简单易懂的(我也不知道网上说spring security难,难在哪里),简单不需要特别的功能,一个WebSecurityConfigurerAdapter的实现,然后实现UserServiceDetails就是简单的数据库验证了,这个我就不说了。

      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的验证工作流程就是这样了。

    开始配置多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 方法就是验证过程。

      如果AuthenticationProvider返回了null,AuthenticationManager会交给下一个支持authentication类型的AuthenticationProvider处理。

    另外需要一个数据库认证的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,在里面做各种认证也是可以的~不过这样就没意思了

  • 相关阅读:
    【 Java框架】Spring的核心IOC源码分析
    小猪学设计模式——模板方法模式
    小猪学设计模式——工厂模式之抽象工厂
    小猪学设计模式——工厂模式之工厂方法模式
    小猪学设计模式——工厂模式之简单工厂(静态工厂)
    HTML5 Server-sent Events ASP.NET向Web客户端推送信息
    jquery.min.map 404 (Not Found)
    C# HTTP 断点续传
    C#操作JSON字符串
    Visual Studio 解决Windows Web服务框架中出现了无法识别的错误
  • 原文地址:https://www.cnblogs.com/scau-chm/p/6836748.html
Copyright © 2020-2023  润新知