前言:

CaptchaAuthenticationFilter是通过模仿UsernamePasswordAuthenticationFilter实现的。同样的道理,由于UsernamePasswordAuthenticationFilter的配置是由FormLoginConfigurer来完成的,应该也能模仿一下FormLoginConfigurer,写一个配置类CaptchaAuthenticationFilterConfigurer去配置CaptchaAuthenticationFilter

public final class FormLoginConfigurer<H extends HttpSecurityBuilder<H>> extends
		AbstractAuthenticationFilterConfigurer<H, FormLoginConfigurer<H>, UsernamePasswordAuthenticationFilter> {
 
    // 省略
}    

AbstractAuthenticationFilterConfigurer

FormLoginConfigurer看起来有点复杂,不过继承关系并不复杂,只继承了AbstractAuthenticationFilterConfigurer

public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecurityBuilder<B>, T extends AbstractAuthenticationFilterConfigurer<B, T, F>, F extends AbstractAuthenticationProcessingFilter>
		extends AbstractHttpConfigurer<T, B> {
}    

理论上我们模仿一下,也继承一下这个类,但是你会发现这种方式行不通。因为AbstractAuthenticationFilterConfigurer只能Spring Security内部使用,不建议自定义。原因在于它最终向HttpSecurity添加过滤器使用的是HttpSecurity.addFilter(Filter)方法,这个方法只有内置过滤器(参见FilterOrderRegistration)才能使用。了解了这个机制之后,我们只能往上再抽象一层,去改造其父类AbstractHttpConfigurer

改造过程

AbstractAuthenticationFilterConfigurer<B,T,F>中的B是实际指的HttpSecurity,因此这个要保留;

T指的是它本身的实现,我们配置CaptchaAuthenticationFilter不需要下沉一层到FormLoginConfigurer这个继承级别,直接在AbstractAuthenticationFilterConfigurer这个继承级别实现即可,因此T这里指的就是需要配置类本身,也不需要再抽象化,因此是不需要的;同样的原因F也不需要,很明确是CaptchaAuthenticationFilter,不需要再泛化。这样CaptchaAuthenticationFilter的配置类结构可以这样定义:

public class CaptchaAuthenticationFilterConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractHttpConfigurer<CaptchaAuthenticationFilterConfigurer<H>, H> {
    // 不再泛化  具体化 
    private final CaptchaAuthenticationFilter authFilter;
    // 特定的验证码用户服务
    private CaptchaUserDetailsService captchaUserDetailsService;
    // 验证码处理服务
    private CaptchaService captchaService;
    // 保存认证请求细节的策略 
    private AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource;
    // 默认使用保存请求认证成功处理器 
    private SavedRequestAwareAuthenticationSuccessHandler defaultSuccessHandler = new SavedRequestAwareAuthenticationSuccessHandler();
    // 认证成功处理器
    private AuthenticationSuccessHandler successHandler = this.defaultSuccessHandler;
     // 登录认证端点
    private LoginUrlAuthenticationEntryPoint authenticationEntryPoint;
    // 是否 自定义页面 
    private boolean customLoginPage;
    // 登录页面
    private String loginPage;
    // 登录成功url
    private String loginProcessingUrl;
    // 认证失败处理器
    private AuthenticationFailureHandler failureHandler;
    // 认证路径是否放开
    private boolean permitAll;
    //  认证失败的url
    private String failureUrl;

    /**
     * Creates a new instance with minimal defaults
     */
    public CaptchaAuthenticationFilterConfigurer() {
        setLoginPage("/login/captcha");
        this.authFilter = new CaptchaAuthenticationFilter();
    }
    public CaptchaAuthenticationFilterConfigurer<H> formLoginDisabled() {
        this.formLoginEnabled = false;
        return this;
    }
    public CaptchaAuthenticationFilterConfigurer<H> captchaUserDetailsService(CaptchaUserDetailsService captchaUserDetailsService) {
        this.captchaUserDetailsService = captchaUserDetailsService;
        return this;
    }
    public CaptchaAuthenticationFilterConfigurer<H> captchaService(CaptchaService captchaService) {
        this.captchaService = captchaService;
        return this;
    }
    public CaptchaAuthenticationFilterConfigurer<H> usernameParameter(String usernameParameter) {
        authFilter.setUsernameParameter(usernameParameter);
        return this;
    }
    public CaptchaAuthenticationFilterConfigurer<H> captchaParameter(String captchaParameter) {
        authFilter.setCaptchaParameter(captchaParameter);
        return this;
    }
    public CaptchaAuthenticationFilterConfigurer<H> parametersConverter(Converter<HttpServletRequest, CaptchaAuthenticationToken> converter) {
        authFilter.setConverter(converter);
        return this;
    }
    @Override
    public void init(H http) throws Exception {
        updateAuthenticationDefaults();
        updateAccessDefaults(http);
        registerDefaultAuthenticationEntryPoint(http);
        // 这里禁用默认页面过滤器 如果你想自定义登录页面 可以自行实现 可能和FormLogin冲突
        // initDefaultLoginFilter(http);
        // 把对应的Provider也在init时写入HttpSecurity
        initProvider(http);
    }
     @Override
    public void configure(H http) throws Exception {
        //这里改为使用前插过滤器方法
         http.addFilterBefore(filter, LogoutFilter.class);
    }
     // 其它方法 同AbstractAuthenticationFilterConfigurer
}  

其实就是模仿AbstractAuthenticationFilterConfigurer及其实现类的风格把用的配置项实现一边。这里值得一提的是CaptchaService的配置也可以从Spring IoC中查找(参考getBeanOrNull方法,这个方法在Spring Security中随处可见,建议借鉴),这样更加灵活,既能从方法配置也能自动注入。

    private void initProvider(H http) {
        ApplicationContext applicationContext = http.getSharedObject(ApplicationContext.class);
        // 没有配置CaptchaUserDetailsService就去Spring IoC获取
        if (captchaUserDetailsService == null) {
            captchaUserDetailsService = getBeanOrNull(applicationContext, CaptchaUserDetailsService.class);
        }
        // 没有配置CaptchaService就去Spring IoC获取
        if (captchaService == null) {
            captchaService = getBeanOrNull(applicationContext, CaptchaService.class);
        } 
        // 初始化 Provider
        CaptchaAuthenticationProvider captchaAuthenticationProvider = this.postProcess(new CaptchaAuthenticationProvider(captchaUserDetailsService, captchaService));
        // 会增加到ProviderManager的注册列表中
        http.authenticationProvider(captchaAuthenticationProvider);
    }

配置类效果

我们来看看CaptchaAuthenticationFilterConfigurer的配置效果:

    @Bean
    SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http, UserDetailsService userDetailsService) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
                .mvcMatchers("/foo/**").access("hasAuthority('ROLE_USER')")
                .anyRequest().authenticated()
                .and()
                // 所有的 AbstractHttpConfigurer 都可以通过apply方法加入HttpSecurity
                .apply(new CaptchaAuthenticationFilterConfigurer<>())
                // 配置验证码处理服务   这里直接true 方便测试
                .captchaService((phone, rawCode) -> true)
                // 通过手机号去拿验证码,这里为了方便直接写死了,实际phone和username做个映射  
                .captchaUserDetailsService(phone -> userDetailsService.loadUserByUsername("felord"))
                // 默认认证成功跳转到/路径  这里改造成把认证信息直接返回json
                .successHandler((request, response, authentication) -> {
                // 这里把认证信息以JSON形式返回
                    ServletServerHttpResponse servletServerHttpResponse = new ServletServerHttpResponse(response);
                    MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
                           mappingJackson2HttpMessageConverter.write(authentication, MediaType.APPLICATION_JSON,servletServerHttpResponse);
                });
        return http.build();
    }

是不是要优雅很多,解决了你自己配置过滤器的很多疑难杂症。学习一定要模仿,先模仿成功,然后再分析思考为什么会模仿成功,最后形成自己的创造力。千万不要被一些陌生概念唬住,有些改造是不需要去深入了解细节的。

到此这篇关于Java中的Spring Security配置滤器的文章就介绍到这了,更多相关Spring Security过滤器内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!

Java中的Spring Security配置过滤器的更多相关文章

  1. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  2. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  3. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  4. Spring JdbcTemplate执行数据库操作详解

    JdbcTemplate是Spring框架自带的对JDBC操作的封装,目的是提供统一的模板方法使对数据库的操作更加方便、友好,效率也不错,这篇文章主要介绍了Spring JdbcTemplate执行数据库操作,需要的朋友可以参考下

  5. Java实现世界上最快的排序算法Timsort的示例代码

    Timsort 是一个混合、稳定的排序算法,简单来说就是归并排序和二分插入排序算法的混合体,号称世界上最好的排序算法。本文将详解Timsort算法是定义与实现,需要的可以参考一下

  6. Spring Batch批处理框架操作指南

    Spring Batch 是 Spring 提供的一个数据处理框架。企业域中的许多应用程序需要批量处理才能在关键任务环境中执行业务操作,这篇文章主要介绍了Spring Batch批处理框架操作指南,需要的朋友可以参考下

  7. Java日期工具类的封装详解

    在日常的开发中,我们难免会对日期格式化,对日期进行计算,对日期进行校验,为了避免重复写这些琐碎的逻辑,我这里封装了一个日期工具类,方便以后使用,直接复制代码到项目中即可使用,需要的可以参考一下

  8. Java设计模式之模板方法模式Template Method Pattern详解

    在我们实际开发中,如果一个方法极其复杂时,如果我们将所有的逻辑写在一个方法中,那维护起来就很困难,要替换某些步骤时都要重新写,这样代码的扩展性就很差,当遇到这种情况就要考虑今天的主角——模板方法模式

  9. Java 中 Class Path 和 Package的使用详解

    这篇文章主要介绍了Java 中 Class Path和Package的使用详解,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的朋友可以参考一下

  10. java SpringBoot 分布式事务的解决方案(JTA+Atomic+多数据源)

    这篇文章主要介绍了java SpringBoot 分布式事务的解决方案(JTA+Atomic+多数据源),文章围绕主题展开详细的内容介绍,具有一定的参考价值,感兴趣的小伙伴可以参考一下

随机推荐

  1. 基于EJB技术的商务预订系统的开发

    用EJB结构开发的应用程序是可伸缩的、事务型的、多用户安全的。总的来说,EJB是一个组件事务监控的标准服务器端的组件模型。基于EJB技术的系统结构模型EJB结构是一个服务端组件结构,是一个层次性结构,其结构模型如图1所示。图2:商务预订系统的构架EntityBean是为了现实世界的对象建造的模型,这些对象通常是数据库的一些持久记录。

  2. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  3. Mybatis分页插件PageHelper手写实现示例

    这篇文章主要为大家介绍了Mybatis分页插件PageHelper手写实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  4. (jsp/html)网页上嵌入播放器(常用播放器代码整理)

    网页上嵌入播放器,只要在HTML上添加以上代码就OK了,下面整理了一些常用的播放器代码,总有一款适合你,感兴趣的朋友可以参考下哈,希望对你有所帮助

  5. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  6. Java异常Exception详细讲解

    异常就是不正常,比如当我们身体出现了异常我们会根据身体情况选择喝开水、吃药、看病、等 异常处理方法。 java异常处理机制是我们java语言使用异常处理机制为程序提供了错误处理的能力,程序出现的错误,程序可以安全的退出,以保证程序正常的运行等

  7. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  8. 面试突击之跨域问题的解决方案详解

    跨域问题本质是浏览器的一种保护机制,它的初衷是为了保证用户的安全,防止恶意网站窃取数据。那怎么解决这个问题呢?接下来我们一起来看

  9. Mybatis-Plus接口BaseMapper与Services使用详解

    这篇文章主要为大家介绍了Mybatis-Plus接口BaseMapper与Services使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  10. mybatis-plus雪花算法增强idworker的实现

    今天聊聊在mybatis-plus中引入分布式ID生成框架idworker,进一步增强实现生成分布式唯一ID,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部