zoukankan      html  css  js  c++  java
  • 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;
        }
    }
    View Code

      该类继承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;
        }
    }
    View Code

    自定义授权方式,在这里接收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());
        }
    }
    View Code

       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);
        }
    }
    View Code

      在这里面我们通过HttpSecurity的方法来添加我们自定义的filter,一定要注意先后顺序。在AuthenticationManagerBuilder当中还需要添加我们刚才定义的 AuthenticationProvider

    启动成功后,我们将Student表里的jointime值改为早于今天的时间,进行登录可以发现:

  • 相关阅读:
    Vue+ElementUI 安装与应用
    python 之serial、pyusb 使用开发
    ASP.NET Swagger 创建与汉化生成 API说明文档
    DataGridView绑定数据源后动态删除行
    MySql动态拼接SQL并动态赋值
    MySql存储过程
    DEV控件之TreeList使用
    DataGridView单元格格式化
    ajax通过PUT方式调用WEBAPI
    解决跨域session 同步问题
  • 原文地址:https://www.cnblogs.com/niechen/p/9174096.html
Copyright © 2011-2022 走看看