详解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,在里面做各种认证也是可以的~不过这样就没意思了
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
推荐阅读
-
详解spring security 配置多个AuthenticationProvider
-
Spring Java-based容器配置详解
-
Spring Boot Hazelcast Caching 使用和配置详解
-
Spring Boot Log4j2的配置使用详解
-
Spring Security认证提供程序示例详解
-
详解Spring Boot 使用slf4j+logback记录日志配置
-
Spring Boot打包部署和环境配置详解
-
Spring Boot Redis 集成配置详解
-
详解最简单易懂的Spring Security 身份认证流程讲解
-
基于Spring Boot的Environment源码理解实现分散配置详解