SpringSecurity学习之自定义过滤器的实现代码
我们系统中的认证场景通常比较复杂,比如说用户被锁定无法登录,限制登录ip等。而springsecuriy最基本的是基于用户与密码的形式进行认证,由此可知它的一套验证规范根本无法满足业务需要,因此扩展势在必行。那么我们可以考虑自己定义filter添加至springsecurity的过滤器栈当中,来实现我们自己的验证需要。
本例中,基于前篇的数据库的student表来模拟一个简单的例子:当student的jointime在当天之后,那么才允许登录
一、创建自己定义的filter
我们先在web包下创建好几个包并定义如下几个类
customerauthfilter:
package com.bdqn.lyrk.security.study.web.filter; import com.bdqn.lyrk.security.study.web.authentication.userjointimeauthentication; import org.springframework.security.authentication.authenticationmanager; import org.springframework.security.core.authentication; import org.springframework.security.core.authenticationexception; import org.springframework.security.web.authentication.abstractauthenticationprocessingfilter; import org.springframework.security.web.util.matcher.antpathrequestmatcher; import javax.servlet.servletexception; import javax.servlet.http.httpservletrequest; import javax.servlet.http.httpservletresponse; import java.io.ioexception; public class customerauthfilter extends abstractauthenticationprocessingfilter { private authenticationmanager authenticationmanager; public customerauthfilter(authenticationmanager authenticationmanager) { super(new antpathrequestmatcher("/login", "post")); this.authenticationmanager = authenticationmanager; } @override public authentication attemptauthentication(httpservletrequest request, httpservletresponse response) throws authenticationexception, ioexception, servletexception { string username = request.getparameter("username"); userjointimeauthentication usernamepasswordauthenticationtoken =new userjointimeauthentication(username); authentication authentication = this.authenticationmanager.authenticate(usernamepasswordauthenticationtoken); if (authentication != null) { super.setcontinuechainbeforesuccessfulauthentication(true); } return authentication; } }
该类继承abstractauthenticationprocessingfilter,这个filter的作用是对最基本的用户验证的处理,我们必须重写attemptauthentication方法。authentication接口表示授权接口,通常情况下业务认证通过时会返回一个这个对象。super.setcontinuechainbeforesuccessfulauthentication(true) 设置成true的话,会交给其他过滤器处理。
二、定义userjointimeauthentication
package com.bdqn.lyrk.security.study.web.authentication; import org.springframework.security.authentication.abstractauthenticationtoken; public class userjointimeauthentication extends abstractauthenticationtoken { private string username; public userjointimeauthentication(string username) { super(null); this.username = username; } @override public object getcredentials() { return null; } @override public object getprincipal() { return username; } }
自定义授权方式,在这里接收username的值处理,其中getprincipal我们可以用来存放登录名,getcredentials可以存放密码,这些方法来自于authentication接口
三、定义authenticationprovider
package com.bdqn.lyrk.security.study.web.authentication; import com.bdqn.lyrk.security.study.app.pojo.student; import org.springframework.security.authentication.authenticationprovider; import org.springframework.security.core.authentication; import org.springframework.security.core.authenticationexception; import org.springframework.security.core.userdetails.userdetails; import org.springframework.security.core.userdetails.userdetailsservice; import java.util.date; /** * 基本的验证方式 * * @author chen.nie * @date 2018/6/12 **/ public class userjointimeauthenticationprovider implements authenticationprovider { private userdetailsservice userdetailsservice; public userjointimeauthenticationprovider(userdetailsservice userdetailsservice) { this.userdetailsservice = userdetailsservice; } /** * 认证授权,如果jointime在当前时间之后则认证通过 * @param authentication * @return * @throws authenticationexception */ @override public authentication authenticate(authentication authentication) throws authenticationexception { string username = (string) authentication.getprincipal(); userdetails userdetails = this.userdetailsservice.loaduserbyusername(username); if (!(userdetails instanceof student)) { return null; } student student = (student) userdetails; if (student.getjointime().after(new date())) return new userjointimeauthentication(username); return null; } /** * 只处理userjointimeauthentication的认证 * @param authentication * @return */ @override public boolean supports(class<?> authentication) { return authentication.getname().equals(userjointimeauthentication.class.getname()); } }
authenticationmanager会委托authenticationprovider进行授权处理,在这里我们需要重写support方法,该方法定义provider支持的授权对象,那么在这里我们是对userjointimeauthentication处理。
四、websecurityconfig
package com.bdqn.lyrk.security.study.app.config; import com.bdqn.lyrk.security.study.app.service.userservice; import com.bdqn.lyrk.security.study.web.authentication.userjointimeauthenticationprovider; import com.bdqn.lyrk.security.study.web.filter.customerauthfilter; import org.springframework.beans.factory.annotation.autowired; import org.springframework.security.config.annotation.authentication.builders.authenticationmanagerbuilder; 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.enablewebsecurity; import org.springframework.security.config.annotation.web.configuration.websecurityconfigureradapter; import org.springframework.security.web.authentication.usernamepasswordauthenticationfilter; /** * spring-security的相关配置 * * @author chen.nie * @date 2018/6/7 **/ @enablewebsecurity public class websecurityconfig extends websecurityconfigureradapter { @autowired private userservice userservice; @override protected void configure(httpsecurity http) throws exception { /* 1.配置静态资源不进行授权验证 2.登录地址及跳转过后的成功页不需要验证 3.其余均进行授权验证 */ http. authorizerequests().antmatchers("/static/**").permitall(). and().authorizerequests().antmatchers("/user/**").hasrole("7022"). and().authorizerequests().anyrequest().authenticated(). and().formlogin().loginpage("/login").successforwardurl("/toindex").permitall() .and().logout().logouturl("/logout").invalidatehttpsession(true).deletecookies().permitall() ; http.addfilterbefore(new customerauthfilter(authenticationmanager()), usernamepasswordauthenticationfilter.class); } @override protected void configure(authenticationmanagerbuilder auth) throws exception { //设置自定义userservice auth.userdetailsservice(userservice); auth.authenticationprovider(new userjointimeauthenticationprovider(userservice)); } @override public void configure(websecurity web) throws exception { super.configure(web); } }
在这里面我们通过httpsecurity的方法来添加我们自定义的filter,一定要注意先后顺序。在authenticationmanagerbuilder当中还需要添加我们刚才定义的authenticationprovider
启动成功后,我们将student表里的jointime值改为早于今天的时间,进行登录可以发现:
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: Java中使用内存映射实现大文件上传实例