SpringSecurity学习之自定义过滤器的实现代码

时间:2021-05-20

我们系统中的认证场景通常比较复杂,比如说用户被锁定无法登录,限制登录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 **/@EnableWebSecuritypublic class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserService userService; @Override protected void configure(HttpSecurity http) throws Exception { 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值改为早于今天的时间,进行登录可以发现:

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

声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。

相关文章