SpringSecurity权限管理框架系列(七)-SpringSecurity自定义配置类中自定义Filter的使用详解

1、Filter请求过滤器

filter请求过滤器可以帮助我们进行HttpServletRequest请求和HttpServletResponse响应的过滤
在自定义的Filter过滤器中我们可以对我们的请求进行过滤, 同时也可以对返回的相应进行处理,在方法中实现我们自定义的业务逻辑处理,这是很常见的需求,下面说说spring security框架中怎么是怎么搭配自定义Filter过滤器来使用的。

2、自定义Spring Security配置类中添加自定义Filter

2.1 自定义Filter类


package com.kkarma.filter;

import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class MyFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        System.out.println("myFilter 被执行了...");
        filterChain.doFilter(request, response);
    }
}

解释下为什么继承自OncePerRequestFilter这个类,OncePerRequestFilter是Spring Boot里面的一个过滤器抽象类,这个类的作用就是用于继承实现并在每次请求时只执行一次过滤,如果想知道详细的实现原理,可以自行翻阅源码, 实现也比较简单, 一看就懂。

2.2 在自定义的spring security配置类中配置myFilter

filter的实现使用了设计模式中的责任链模式,在添加自定义的filter时,可以有很多方时,可以指定将自定义的Filter添加到某个指定的Filter之前或者之后,具体怎么实现看用户自己的选择, 如果对于方法不了解, 可以进入到方法里面,看看方法的注释,说的都比较清楚。
SpringSecurity权限管理框架系列(七)-SpringSecurity自定义配置类中自定义Filter的使用详解_第1张图片
注入自定义Filter的bean对象
SpringSecurity权限管理框架系列(七)-SpringSecurity自定义配置类中自定义Filter的使用详解_第2张图片
将自定义Filter的bean对象添加到过滤器链中的用户登录认证校验过滤器之前
SpringSecurity权限管理框架系列(七)-SpringSecurity自定义配置类中自定义Filter的使用详解_第3张图片
完整配置类代码

package com.kkarma.config;

import com.kkarma.filter.MyFilter;
import com.kkarma.handler.CustomAccessDeniedHandler;
import com.kkarma.web.service.impl.MyUserDetailsServiceImpl;
import org.apache.coyote.Adapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;


@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class CustomWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {

    /**
     * 自定义Filter
     */
    @Autowired
    private MyFilter myFilter;

    @Autowired
    private CustomAccessDeniedHandler accessDeniedHandler;

    /**
     * 自定义用户认证逻辑
     */
    @Autowired
    private UserDetailsService userDetailsService;


    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception
    {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        /**
         * 配置csrf开启关闭,默认是开启的
         */
          http.csrf().disable();

        /**
         * 表单登录相关的配置
         */
//        http.formLogin()
                // 前端登录表单用户名别名, 从参数user中获取username参数取值
                // .usernameParameter("user")
                // 前端登录表单密码别名, 从参数passwd中获取password参数取值
                // .passwordParameter("passwd")
                // 当http请求的url是/login时,进行我们自定义的登录逻辑
                // .loginProcessingUrl("/login")
                // 自定义登录的前端控制器
                // .loginPage("/showLogin")
                // 设置登录成功的跳转链接
                // .successForwardUrl("/home");
                // 通过successHandler处理器进行登录成功之后的逻辑处理
                // .successHandler(new AuthenticationSuccessHandler() {
                //    @Override
                //    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                //        System.out.println("登录成功,页面即将跳转...");
                //        Collection authorities = authentication.getAuthorities();
                //        authorities.forEach(System.out::println);
                //        response.sendRedirect("/home");
                //    }
                // })
                // 设置登录失败的跳转链接
                // .failureForwardUrl("/errPage");
                // 通过failureHandler处理器进行登录失败之后的逻辑处理
                // .failureHandler(new AuthenticationFailureHandler() {
                //    @Override
                //    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
                //        e.printStackTrace();
                //        System.out.println("登录失败,页面即将跳转到默认失败页...");
                //        response.sendRedirect("/errPage");
                //    }
                // })
//                .and()



        // 用户退出登录处理配置
        http
            // 403权限不足异常使用自定义403处理器处理
            .exceptionHandling().accessDeniedHandler(accessDeniedHandler)
            .and()
            // 基于token,所以不需要session
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
            .logout()
            // 用户退出成功之后的跳转链接
            .logoutSuccessUrl("/showLogin")
            // 设置用户退出的url
            .logoutUrl("/logout")
            // 自定义用户的退出逻辑处理器, 可以处理认证信息、session、cookies等信息
            .addLogoutHandler(new LogoutHandler() {
                @Override
                public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
                    // 这里可以自定义用户退出的处理逻辑
                    System.out.println("退出成功...");
                }
            })
            // 是否清除认证状态,默认为true
            .clearAuthentication(true)
            // 是否销毁HttpSession对象,默认为true
            .invalidateHttpSession(true);


        /**
         * http请求是否要登录认证配置
         */
        http.authorizeRequests()
                // 允许GET请求登录页面匿名访问
                .antMatchers(HttpMethod.GET, "/showLogin", "/errPage", "/captchaImage").anonymous()
                .antMatchers(HttpMethod.POST, "/login").anonymous()
                // 匹配所有名称以demo结尾的js并允许匿名访问
                .regexMatchers(HttpMethod.GET, ".+demo[.]js").anonymous()
                // 用户具有admin角色时允许访问/role
                .antMatchers(HttpMethod.GET, "/role").hasRole("admin")
                // 用户具有system:user权限时允许访问/role
                .antMatchers(HttpMethod.GET, "/role").hasAuthority("system:user")
                // 所有的静态资源允许匿名访问
                .antMatchers(
                        "/css/**",
                        "/js/**",
                        "/images/**",
                        "/fonts/**",
                        "/favicon.ico"
                        ).anonymous()
                // 其他所有的请求都需要登录认证
                .anyRequest().authenticated()
                .and()
                // 意思就是在登录认证校验过滤器执行之前先进行自定义过滤器myFilter的执行
                .addFilterBefore(myFilter, UsernamePasswordAuthenticationFilter.class)
        ;
    }

    /**
     * 身份认证接口
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception
    {
        auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
    }

    /**
     * 在内存中预置两个演示用户admin和common
     */
//    @Override
//    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//
//        auth.inMemoryAuthentication()
//                .withUser("admin")
//                .password(bCryptPasswordEncoder().encode("123456"))
//                .roles("admin", "superAdmin")
//                .authorities(AuthorityUtils.commaSeparatedStringToAuthorityList("system,sytem:user,system:user:list"))
//                .and()
//                .withUser("common")
//                .password(bCryptPasswordEncoder().encode("123456"))
//                .roles("common")
//                .authorities(AuthorityUtils.commaSeparatedStringToAuthorityList("good,good:cate,good:cate:list"));
//    }

    /**
     * 强散列哈希加密实现
     */
    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder()
    {
        return new BCryptPasswordEncoder();
    }
}

启动项目, 看看filter是否生效,随便发送一个请求,看到我们定义的myFilter被执行了,我们可以在这个过滤器里面添加自己的逻辑实现
SpringSecurity权限管理框架系列(七)-SpringSecurity自定义配置类中自定义Filter的使用详解_第4张图片

你可能感兴趣的:(Spring全家桶,Spring,Security,spring,security,权限框架,spring)