述
上文中,实现了一个简单的图形验证码,但是这个是写死的, 图片的长宽,验证码的位数都是写死的,然后我们希望做成一个可配置的,就是由调用方去决定这些可变的参数
还有验证码拦截的接口,我们现在是只拦截登录请求,这个也可以做成一个可配置的,由调用方去决定,拦截哪些请求
最后就是把验证码的生成逻辑也做成可配置的,由我们的项目提供一个默认的生成逻辑,然后调用方可以去覆盖的这种
验证码参数可配置
跟之前配置过的登录页一样,首先我们的安全模块里面先给一个默认的配置, 然后调用安全模块的项目可以覆盖掉这个配置,最后,验证码的长和宽可以通过前端发的参数覆盖掉应用级的配置(不同的页面可能长宽不一样),如下图:
跟之前的登录页配置是一样的 ,这里我们需要一个放图形验证码的配置的配置类 ImageCodeProperties
,代码如下:
1 | @Data |
然后把这个类再包一层,新建一个 ValidateCodeProperties
,因为后面可能还有别的验证码,所以这里再包一层,代码如下:
1 | @Data |
最后放到总的配置 SecurityProperties
中去,如下:
1 | @Data |
这样在调用方,也就是demo项目中的 application.yml
,就可以配置验证码的参数了, 如下:
1 | core: |
这里就是设置了验证码的长度是6位,我们默认的是4位
最后就是请求级的配置了,修改 ValidateCodeController
,修改后的代码如下:
1 | @RestController |
这里主要是修改了 createImageCode()
方法,长和宽先从request中去取, 取不到的话,就从配置中取,就是我们之前写死的参数,都通过配置去拿
测试
到这儿,验证码的基本参数可配置就修改完成了,最后可以在页面中拿验证码的请求中加上参数,如下:
1 | <img src="/code/image?width=200"> |
这里请求中指定了验证码的长度是200, 然后上面 application.yml
中指定了验证码的长度是6, 然后启动项目,看下效果,如图:
可以看到,不论是请求的配置还是应用级的配置都生效了
验证码拦截接口可配置
在我们之前的 ValidateCodeFilter
中,是只拦截了一个 /authentication/from
这个登录的请求,我们在其他请求中,也可能需要用到图片验证码,所以这里的拦截可以做成一个可配置的拦截,下面来看一下具体的实现
首先在 ImageCodeProperties
增加一个属性
1 | /** |
这样的话,在应用中的 application.yml
中,就可以配置了, 如下:
1 | core: |
这里我们使用了通配符去匹配
然后修改过滤器 ValidateCodeFilter
中的判断, 部分修改后的代码如下:
1 | @Data |
这里首先是实现了一个 InitializingBean
目的是为了在其他的参数都组装完毕之后,初始化urls的值
然后重写了 afterPropertiesSet()
方法,里面把配置中的urls取出来,加到set集合中去
后面修改了doFilterInternal()
方法中的判断逻辑, 因为我们使用了通配符的这种,所以用到了 AntPathMatcher
去做验证
最后需要在配置类 BrowserSecurityConfig
中修改配置, 如下:
1 | @Override |
就是把过滤器里面需要用到的 securityProperties
传了进去,然后调用了初始化属性的方法
测试
上面的配置都ok之后,就可以启动项目看下效果了, 我们在 application.yml
中配置的是 /user/**,/test/*
可覆盖的图形验证码逻辑
我们上面生成的图形验证码,逻辑是写死的,只能按照我们写死的逻辑来,现在我们想实现的就是,我们这个生成图片验证码的逻辑作为一个默认的方式,然后调用方可以自己去重写一个逻辑来覆盖我们的这个逻辑,下面看一下如何实现:
首先需要声明一个接口 ValidateCodeGenerator
,代码如下:
1 | public interface ValidateCodeGenerator { |
然后需要一个实现类,把实现图形验证码的代码都放在里面,新建 ImageCodeGenerator
, 代码如下:
1 | @Data |
这里就是把controller中的逻辑都复制过来了,然后controller中的代码需要修改一下,如下:
1 | @RestController |
就是把我们刚刚创建的生成器注入进来,这里调用就ok
到这儿,我们已经把验证码的生成逻辑放到一个接口的实现里面去了, 那如何把这个接口的实现改成可配置的,这里还需要加一个配置类,新建 ValidateCodeBeanConfig
,代码如下:
1 | @Configuration |
这里就是把我们的 ImageCodeGenerator
交给 Spring 去管理, 这里的重点是 @ConditionalOnMissingBean(name = "imageCodeGenerator")
这个注解的意思是,首先先会在容器中找一个名字是 imageCodeGenerator
的bean,找到的话就用找到的,找不到的话,再用我们下面方法中实例化的那个bean
有了这个注解就可以实现应用层的重写覆盖了
到这里就可以先看一下效果了, 因为我们并没有在应用层重写生成的逻辑,所以还是用的默认的逻辑,如下:
应用层覆盖实现逻辑
最后我们在应用层,也就是 demo
项目中,重新写一个图片验证码的生成器,新建一个类,实现我们的 ValidateCodeGenerator
接口,代码如下:
1 | @Slf4j |
具体的生成逻辑这里就不写了,主要是@Component("imageCodeGenerator")
这个注解,这里的名字要和上面配置的 @ConditionalOnMissingBean(name = "imageCodeGenerator")
名字对应, 然后启动项目看下效果
这里已经进入到我们的应用层中的逻辑了,因为这儿返回的是空所以会报空指针
总结
这里,我们的一个可配置的图形验证码的逻辑就实现了, 主要是以下几点
- 实现
InitializingBean
接口,重写afterPropertiesSet()
方法可以在其他的参数都组装完毕之后,做一些初始化的逻辑 - 使用
@Bean
注入一个bean的时候可以@ConditionalOnMissingBean
来做一个条件,如果条件不满足的情况下,才使用@Bean
注入