详解spring security 配置多个AuthenticationProvider

 更新时间:2017年05月11日 09:56:13   作者:暮夜望日  
这篇文章主要介绍了详解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;
  }
}

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

最后在WebSecurityConfigurerAdapter里配置一个含有以上两个AuthenticationProvider的AuthenticationManager,依然重用spring security提供的ProviderManager

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()));
    //不擦除认证密码,擦除会导致TokenBasedRememberMeServices因为找不到Credentials再调用UserDetailsService而抛出UsernameNotFoundException
    authenticationManager.setEraseCredentialsAfterAuthentication(false);
    return authenticationManager;
  }

  /**
   * 这里需要提供UserDetailsService的原因是RememberMeServices需要用到
   * @return
   */
  @Override
  protected UserDetailsService userDetailsService() {
    return userServiceDetails;
  }
}

基本上都是重用了原有的类,很多都是默认使用的,只不过为了修改下行为而重新配置。其实如果偷懒,直接用一个UserDetailsService,在里面做各种认证也是可以的~不过这样就没意思了

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • maven插件maven-jar-plugin构建jar文件的详细使用

    maven插件maven-jar-plugin构建jar文件的详细使用

    maven-jar-plugin插件时maven中最常用的插件,也是maven构建Java程序执行包或者依赖包的默认插件,本文主要介绍了maven插件maven-jar-plugin构建jar文件的详细使用,具有一定的参考价值,感兴趣的可以了解一下
    2024-02-02
  • JavaIO BufferedReader和BufferedWriter使用及说明

    JavaIO BufferedReader和BufferedWriter使用及说明

    这篇文章主要介绍了JavaIO BufferedReader和BufferedWriter使用及说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-12-12
  • Java服务假死之生产事故的排查与优化问题

    Java服务假死之生产事故的排查与优化问题

    在服务器上通过curl命令调用一个Java服务的查询接口,半天没有任何响应,怎么进行这一现象排查呢,下面小编给大家记一次生产事故的排查与优化——Java服务假死问题,感兴趣的朋友一起看看吧
    2022-07-07
  • spring为类的静态属性实现注入实例方法

    spring为类的静态属性实现注入实例方法

    在本篇文章里小编给大家整理的是关于spring为类的静态属性实现注入实例方法,有需要的朋友们可以参考下。
    2019-10-10
  • Spring的编程式事务TransactionTemplate的用法详解

    Spring的编程式事务TransactionTemplate的用法详解

    TransactionTemplate提供了一种在代码中进行编程式事务管理的方式,使开发人员能够在方法级别定义事务的开始和结束点,本文介绍了Spring框架中TransactionTemplate的用法,感兴趣的朋友跟随小编一起看看吧
    2023-07-07
  • SpringBoot最简洁的国际化配置

    SpringBoot最简洁的国际化配置

    这篇文章主要介绍了SpringBoot最简洁的国际化配置,Spring Boot是一个用于构建独立的、生产级别的Spring应用程序的框架,国际化是一个重要的功能,它允许应用程序根据用户的语言和地区显示不同的内容,在Spring Boot中,实现国际化非常简单,需要的朋友可以参考下
    2023-10-10
  • Maven仓库的具体使用(本地仓库+远程仓库)

    Maven仓库的具体使用(本地仓库+远程仓库)

    Maven 在某个统一的位置存储所有项目的构件,这个统一的位置,我们就称之为仓库,本文主要介绍了Maven仓库的具体使用(本地仓库+远程仓库),感兴趣的可以了解一下
    2023-11-11
  • Spring Cloud Data Flow初体验以Local模式运行

    Spring Cloud Data Flow初体验以Local模式运行

    这篇文章主要介绍了Spring Cloud Data Flow初体验以Local模式运行,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-08-08
  • spring 自动注入AutowiredAnnotationBeanPostProcessor源码解析

    spring 自动注入AutowiredAnnotationBeanPostProcessor源码解析

    这篇文章主要介绍了spring自动注入AutowiredAnnotationBeanPostProcessor源码解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-03-03
  • 如何解决Spring in action @valid验证不生效的问题

    如何解决Spring in action @valid验证不生效的问题

    这篇文章主要介绍了如何解决Spring in action @valid验证不生效的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-06-06

最新评论