有关SpringSceurity系列之前有写文章
一、思考
1、设计思路
在获取短信验证码功能和图形验证码还是有很多相似的地方,所以这里在设计获取短信验证的时候,将之前开发好的的图形验证码进一步整合、抽象与重构。
在获取验证码的时候,它们最大的不同在于: 图形验证码是通过接口返回获取給前端。而短信验证码而言是通过第三方API向我们手机推送。
但是它们在登陆的时候就有很大的不同了,对于图形验证码而言验证通过之前就走 UsernamePasswordAuthenticationFilter 过滤器了开始校验用户名密码了。
但对于短信登陆而言,确实也需要先现在短信验证码是否通过,但是一旦通过他是不走 UsernamePasswordAuthenticationFilter,而是通过其它方式查询用户信息来校验
认证已经通过了。
这篇博客只写获取获取短信验证码的功能,不写通过短信验证码登陆的逻辑。
2、重构设计
这里才是最重要的,如何去设计和整合短信验证码和图形验证码的代码,是我们最应该思考的。如何将相似部分抽离出来,然后去实现不相同的部分。
整理后发现不同点主要在于
- 获取验证码。因为对于图形验证码需要有个画布,而短信验证码并不需要,所以它们可以实现同一个接口,来完成不同的逻辑。
- 发送验证码。对于图形验证码来讲只要把验证码返给前端就可以,而
短信验证码而言是通过第三方API将验证码发到我们的手机上。
所以这里也可以通过实现统一接口来具体实现不同的方法。
相同部分我可以通过抽象类来完成实现,不同部分可以通过具体的实现类来实现。
AbstractValidateCodeProcessorService 抽象类是用来实现两种验证码可以抽离的部分。ImageCodeProcessorServiceImpl 和
SmsCodeProcessorServiceImpl方法是来实现两种验证码不同的发送方式。
在简单看下时序图可能会更加明白点。
不得不说,雨点的名字,大佬真猛
一个接口只有一个方法(processor)就是处理验证码,它其实需要做三件事。
1、获取验证码。
2、将验证码存入session。
3、将验证码信息通过短信或者图形验证码发送出去。
首先讲生成获取验证码,这里有一个公共接口和两个实现类
对于保存验证码信息而言,可以在直接在 AbstractValidateCodeProcessorService抽象类来完成,都不需要去实现。
对发送验证码信息而言,只需要实现AbstractValidateCodeProcessorService抽象类的send发送验证码接口即可。
整个大致接口设计就是这样,具体的可以通过代码来展示。
二、代码实现
1、验证码属性
短信验证码和图形验证后包含属性有 code 和 expireTime,短信验证码只有这两个属性,而图形验证码还多一个BufferedImage实例对象属性,所以将共同属性进行抽取,抽取为ValidateCode类,代码如下:
ValidateCode实体:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ValidateCode {
private String code;
private LocalDateTime expireTime;
public boolean isExpired() {
return LocalDateTime.now().isAfter(expireTime);
}
}
对于图形验证码而言,除了需要code和过期时间还需要图片的画布,所以继承ValidateCode之后再写自己属性
ImageCode实体:
@Data
public class ImageCode extends ValidateCode {
private BufferedImage image;
public ImageCode(BufferedImage image, String code, LocalDateTime expireTime) {
super(code, expireTime);
this.image = image;
}
public ImageCode(BufferedImage image, String code, int expireIn) {
super(code, LocalDateTime.now().plusSeconds(expireIn));
this.image = image;
}
}
对于短信验证码而言,暂时不需要添加自己的属性字段了。
public class SmsCode extends ValidateCode {
public SmsCode(String code, LocalDateTime expireTime) {
super(code, expireTime);
}
public SmsCode(String code, int expireIn) {
super(code, LocalDateTime.now().plusSeconds(expireIn));
}
}
2、ValidateCodeProcessor接口
ValidateCodeProcessor接口主要是完成 验证码的生成、保存与发送的完整流程,接口的主要设计如下所示:
ValidateCodeProcessorService接口:
public interface ValidateCodeProcessorService {
/**
* 因为现在有两种验证码,所以存放到seesion的key不能一样,所以前缀+具体type
*/
String SESSION_KEY_PREFIX = "SESSION_KEY_FOR_CODE_";
/**
* 通过也是 type+CODE_PROCESSOR获取对于的bean
*/
String CODE_PROCESSOR = "CodeProcessorService";
/**
* 这个接口要做三件事
* 1、获取验证码。
* 2、将验证码存入session
* 3、将验证码信息通过短信或者图形验证码发送出去。
* (将spring-boot-security-study-03接口里的那三步进行里封装)
*
*/
void processor(