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

时间:2022-09-23 12:28:43

我们系统中的认证场景通常比较复杂,比如说用户被锁定无法登录,限制登录ip等。而springsecuriy最基本的是基于用户与密码的形式进行认证,由此可知它的一套验证规范根本无法满足业务需要,因此扩展势在必行。那么我们可以考虑自己定义filter添加至springsecurity的过滤器栈当中,来实现我们自己的验证需要。

本例中,基于前篇的数据库的student表来模拟一个简单的例子:当student的jointime在当天之后,那么才允许登录

一、创建自己定义的filter

我们先在web包下创建好几个包并定义如下几个类

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

customerauthfilter:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
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学习之自定义过滤器的实现代码

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

原文链接:https://www.cnblogs.com/niechen/p/9174096.html