我们系统中的认证场景通常比较复杂,比如说用户被锁定无法登录,限制登录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值改为早于今天的时间,进行登录可以发现:

SpringSecurity学习之自定义过滤器的更多相关文章

  1. angularjs学习第三天笔记(过滤器第二篇---filter过滤器及其自定义过滤器)

    您好,我是一名后端开发工程师,由于工作需要,现在系统的从0开始学习前端js框架之angular,每天把学习的一些心得分享出来,如果有什么说的不对的地方,请多多指正,多多包涵我这个前端菜鸟,欢迎大家的点 ...

  2. vue.js学习 自定义过滤器使用(1)

    在这个教程中,我们将会通过几个例子,了解和学习VueJs的过滤器.我们参考了一些比较完善的过滤器,比如orderBy 和 filterBy.而且我们可以链式调用过滤器,一个接一个过滤.因此,我们可以定 ...

  3. Vue.js学习 Item14 – 过滤器与自定义过滤器

    基础 类似于自定义指令,可以用全局方法 Vue.filter() 注册一个自定义过滤器,它接收两个参数:过滤器 ID 和过滤器函数.过滤器函数以值为参数,返回转换后的值: Vue.filter('re ...

  4. vue.js学习 自定义过滤器使用(2)

    gitHub地址: https://github.com/lily1010/vue_learn/tree/master/lesson05 一 自定义过滤器(注册在Vue全局) 注意事项: (1)全局方 ...

  5. SpringCloud学习笔记(19)----Spring Cloud Netflix之服务网关Zuul自定义过滤器

    zuul不仅只是路由,还可以自定义过滤器来实现服务验证. 实现案例:自定义过滤器,检验头部是否带有token,如果token=wangx,则通过校验,若不存在或不为wangx则返回提示token错误. ...

  6. Spring Cloud Alibaba学习笔记(19) - Spring Cloud Gateway 自定义过滤器工厂

    在前文中,我们介绍了Spring Cloud Gateway内置了一系列的内置过滤器工厂,若Spring Cloud Gateway内置的过滤器工厂无法满足我们的业务需求,那么此时就需要自定义自己的过 ...

  7. 小白学习django第三站-自定义过滤器及标签

    要使用自定义过滤器和标签,首先要设置好目录结构 现在项目目录下建立common的python包 再将common加入到setting.py中的INSTALLED_APP列表中 在common创建目录t ...

  8. Spring-Security (学习记录四)--配置权限过滤器,采用数据库方式获取权限

    目录 1. 需要在spring-security.xml中配置验证过滤器,来取代spring-security.xml的默认过滤器 2. 配置securityMetadataSource,可以通过ur ...

  9. Django学习——Django settings 源码、模板语法之传值、模板语法之获取值、模板语法之过滤器、模板语法之标签、自定义过滤器、标签、inclusion_tag、模板的导入、模板的继承

    Django settings 源码 """ 1.django其实有两个配置文件 一个是暴露给用户可以自定义的配置文件 项目根目录下的settings.py 一个是项目默 ...

随机推荐

  1. typecho 文章归档调用

    <style> div { display: block; } .title { position: relative; margin: 0; line-height: 32px; fon ...

  2. vue2.0路由-路由嵌套

    vue一个重要的方面就是路由,下面是自己写的一个路由的例子: 1.引入依赖库就不必再说 2.创建组件 两种写法 第一种:间接 <template id="home"> ...

  3. winSockets编程(三)最简单的C/S形式

    功能:向服务器端发送一个字符串,属于最简易的形式,一共需要4个主要步骤,初始化-建立套接字-连接服务器-发送数据 /****************************************** ...

  4. Ng第七课:正则化与过拟合问题 Regularization/The Problem of Overfitting

    7.1  过拟合的问题 7.2  代价函数 7.3  正则化线性回归 7.4  正则化的逻辑回归模型 7.1  过拟合的问题 如果我们有非常多的特征,我们通过学习得到的假设预测可能能够非常好地适应训练 ...

  5. day34(注解)

    注解 注解和注释的区别: 注释:是给程序员看的. 注解:是给虚拟机识别的. 注解的作用: 1.代替配置文件 2.标识一个方法,代替一个特殊功能. JDK当中的提供的注解: 标识重写方法 @Overri ...

  6. 20169207《Linux内核原理与分析》第九周作业

    第九周的实验依旧和往常的一样,主要包括两部分.一是1.阅读学习教材「Linux内核设计与实现 (Linux Kernel Development)」第教材第13,14章.二是学习MOOC「Linux内 ...

  7. Java的String类

    String类 String是引用数据类型:字符串是String类的对象 String类的构造方法 共有13种重载方式,这里只示例常用的几个 String():创建一个空字符串 String(Stri ...

  8. oracle数据库 ORA-01017的解决办法

    alter user 用户名 identified by 新密码:

  9. AngularJS AOP 实例

    AngularJS有种机制叫做拦截器(interceptor),它是$http扩展点,类似ASP.NET MVC的过滤器filter机制,对每个$http请求的发送和接收过程进行过滤. $httpPr ...

  10. Java学习---- 数组的引用传递

    1. public class ArrayRefDemo01{ public static void main(String args[]){ int temp[] = {1,3,5} ; // 利用 ...