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值改为早于今天的时间,进行登录可以发现:

  • 相关阅读:
    jvm基本结构和解析
    多态的意思
    java中对象的简单解读
    double类型和int类型的区别
    python 解析xml文件
    win10不能映射Ubuntu共享文件
    Qt程序打包
    Ubuntu boot分区文件误删,系统无法启动,怎么解
    ubuntu Boot空间不够问题“The volume boot has only 5.1MB disk space remaining”
    Ubuntu 分辨率更改 xrandr Failed to get size of gamma for output default
  • 原文地址:https://www.cnblogs.com/niechen/p/9174096.html
Copyright © 2011-2022 走看看