欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

详解spring security 配置多个AuthenticationProvider

程序员文章站 2024-02-24 17:34:36
前言 发现很少关于spring security的文章,基本都是入门级的,配个userservicedetails或者配个路由控制就完事了,而且很多还是xml配置,国内通...

前言

发现很少关于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,在里面做各种认证也是可以的~不过这样就没意思了

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