之前胖哥带着大家使用SpringSecurity过滤器实现手机验证码认证。今天我们来完善一下验证码认证的配置方法。这绝对是绝活666,不看了还喜欢?天天白嫖,晚上睡得着吗?CaptchaAuthenticationFilter,验证码过滤器,是模仿UsernamePasswordAuthenticationFilter实现的。同理,既然UsernamePasswordAuthenticationFilter的配置是由FormLoginConfigurer完成的,那么应该可以仿照FormLoginConfigurer写一个配置类CaptchaAuthenticationFilterConfigurer来配置CaptchaAuthenticationFilter。公共最终类FormLoginConFigurer>扩展了AbstractAuthenticationFilterConfigurer,USERNAMEPASSWordAuthenticationFilter>{//publicabstractclassAbstractAuthenticationFilterConfigurer,TextendsAbstractAuthenticationFilterConfigurer,FextendsAbstractAuthenticationProcessingFilter>extendsAbstractHttpConfigurer{}理论上也可以继承这个类你会发现这个方法不起作用。因为AbstractAuthenticationFilterConfigurer只能被SpringSecurity内部使用,所以不建议自定义。原因是它最终使用HttpSecurity.addFilter(Filter)方法为HttpSecurity添加了一个过滤器,该方法只能由内置过滤器使用(参见FilterOrderRegistration)。了解了这个机制之后,我们只能再抽象一层,对其父类AbstractHttpConfigurer进行改造。改造过程中,AbstractAuthenticationFilterConfigurer中的B实际引用的是HttpSecurity,所以这个要保留;T指的是它自己的实现。我们不需要下沉一层到FormLoginConfigurer的继承层来配置CaptchaAuthenticationFilter,直接在AbstractAuthenticationFilterConfigurer的继承层实现即可,所以这里的T指的是需要自己配置类,不需要被抽象出来,所以不需要;同理,F也不需要,明明是CaptchaAuthenticationFilter,就不用再泛化了。Inthisway,theconfigurationclassstructureofCaptchaAuthenticationFiltercanbedefinedasfollows:publicclassCaptchaAuthenticationFilterConfigurer>extendsAbstractHttpConfigurer,H>{//nolongergeneralizeandconcretizeprivatefinalCaptchaAuthenticationFilter;//a码用户服务privateCaptchaUserDetailsServicecaptchaUserDetailsService;//验证码处理服务privateCaptchaServicecaptchaService;//保存认证请求细节的策略privateAuthenticationDetailsSourceauthenticationDetailsSource;//默认使用保存请求认证成功处理器privateSavedRequestAwareAuthenticationSuccessHandlerdefaultSuccessHandler=newSavedRequestAwareAuthenticationSuccessHandler();//authenticationsuccesshandlerprivateAuthenticationSuccessHandlersuccessHandler=this.defaultSuccessHandler;//loginauthenticationendpointprivateLoginUrlAuthenticationEntryPointauthenticationEntryPoint;//whethertocustomizethepageprivatebooleancustomLoginPage;//loginpage私有字符串登录页面;//登录成功urlprivateStringloginProcessingUrl;//认证失败处理器privateAuthenticationFailureHandlerfailureHandler;//认证路径是否放开privatebooleanpermitAll;//认证失败的urlprivateStringfailureUrl;/***创建一个具有最小默认值的新实例*/publicCaptchaAuthenticationFilterConfigurer(){setLoginPage("/login/captcha");this.authFilter=newCaptchaAuthenticationFilter();}publicCaptchaAuthenticationFilterConfigurerformLoginDisabled(){this.formLoginEnabled=false;归还这个;}publicCaptchaAuthenticationFilterConfigurercaptchaUserDetailsS??ervice(CaptchaUserDetailsS??ervicecaptchaUserDetailsS??ervice){this.captchaUserDetailsS??ervice=captchaUserDetailsS??ervice;归还这个;}publicCaptchaAuthenticationFilterConfigurercaptchaService(CaptchaServicecaptchaService){this.captchaService=验证码服务;归还这个;}publicCaptchaAuthenticationFilterConfigurerusernameParameter(StringusernameParameter){authFilter.setUsernameParameter(usernameParameter);归还这个;}publicCaptchaAuthenticationFilterConfigurercaptchaParameter(StringcaptchaParameter){authFilter.setCaptchaParameter(captchaParameter);返回这个;}publicCaptchaAuthenticationFilterConfigurerparametersConverter(Converter转换器){authFilter.setConverter(转换器);归还这个;}@Overridepublicvoidinit(Hhttp)throwsException{updateAuthenticationDefaults();更新访问默认值(http);registerDefaultAuthenticationEntryPoint(http);//在这里禁用默认的页面过滤器。如果要自定义登录页面,可以自己实现,可能会和FormLogin冲突。//初始化默认登录过滤器(http);//初始化时将对应的Provider写入Http安全初始化提供者(http);}@Overridepublicvoidconfigure(Hhttp)throwsException{//这里,使用预插入过滤器的方式来代替http.addFilterBefore(filter,LogoutFilter.class);}//其他方法同AbstractAuthenticationFilterConfigurer}其实就是模仿AbstractAuthenticationFilterConfigurer的风格及其实现类来实现所使用的配置项。这里值得一提的是,CaptchaService的配置也可以从SpringIoC中找到(参考getBeanOrNull方法,在SpringSecurity中随处可见,推荐借鉴)。这更加灵活,无论是从方法配置还是自动注入。privatevoidinitProvider(Hhttp){ApplicationContextapplicationContext=http.getSharedObject(ApplicationContext.class);//去SpringIoC获取CaptchaUserDetailsS??erviceif(captchaUserDetailsS??ervice==null){captchaUserDetailsS??ervice=getBeanOrNull(applicationContext,CaptchaUserDetailsS??ervice.class);}//如果没有配置CaptchaService,去SpringIoC获取if(captchaService==null){captchaService=getBeanOrNull(applicationContext,CaptchaService.class);}//InitializeProviderCaptchaAuthenticationProvidercaptchaAuthenticationProvider=this.postProcess(newCaptchaAuthenticationProvider(captchaUserDetailsS??ervice,captchaService);//会添加到ProviderManager的注册列表中http.authenticationProvider(captchaAuthenticationProvider);}配置效果下面来看看配置效果CaptchaAuthenticationFilterConfigurer:@BeanSecurityFilterChaindefaultSecurityFilterChain(HttpSecurityhttp,UserDetailsServiceuserDetailsS??ervice)抛出异常{http.csrf().disable().authorizeRequests().mvcMatchers("/foo/**").access("hasAuthority('ROLE_USER')").anyRequest().authenticated().and()//所有的AbstractHttpConfigurer都可以通过apply方法添加到HttpSecurity中.apply(newCaptchaAuthenticationFilterConfigurer<>())//这里直接配置验证码处理服务true方便测试.captchaService((phone,rawCode)->true)//使用手机号获取验证码,为了方便直接写在这里,映射了实际的手机和用户名。captchaUserDetailsS??ervice(phone->userDetailsS??ervice.loadUserByUsername("felord"))//默认认证成功跳转到/路径这里转化为直接返回认证信息到json.successHandler((request,response,authentication)->{//这里将认证信息以JSON形式返回给ServletServerHttpResponseservletServerHttpResponse=newServletServerHttpResponse(response);MappingJackson2HttpMessageConvertermappingJackson2HttpMessageConverter=newMappingJackson2HttpMessageConverter();mappingJackson2HttpMessageConverter.write(认证,MediaType.APPLICATION_JSON,servletServerHttpResponse);});返回http。在学习中一定要模仿,先模仿成功,然后分析思考为什么要模仿成功,最后形成自己的创造力。不要被一些不熟悉的概念所迷惑。有些转换不需要深入了解细节。本文转载自微信公众号“码农小胖哥”,可通过以下二维码关注。转载本文请联系码农小胖公众号。