思路:参考用户名密码登录过滤器链,重写认证和授权
示例如下(该篇示例以精简为主,演示主要实现功能,全面完整版会在以后的博文中发出):
由于涉及内容较多,建议先复制到本地工程中,然后在细细研究。
1. 新建Maven项目 sms-code-validate
2. pom.xml
http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
com.java
sms-code-validate
1.0.0
org.springframework.boot
spring-boot-starter-parent
2.0.5.RELEASE
org.springframework.boot
spring-boot-starter-web
org.springframework.cloud
spring-cloud-starter-oauth2
2.0.0.RELEASE
org.springframework.boot
spring-boot-starter-jdbc
com.alibaba
druid
1.1.11
mysql
mysql-connector-java
org.apache.commons
commons-lang3
org.springframework
springloaded
1.2.8.RELEASE
provided
org.springframework.boot
spring-boot-devtools
provided
${project.artifactId}
org.apache.maven.plugins
maven-compiler-plugin
1.8
1.8
UTF-8
org.springframework.boot
spring-boot-maven-plugin
repackage
3. 启动类 SmsCodeStarter.java
packagecom.java;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;/***
*
* 主启动类
*
*
*
*@authorLogan
**/@SpringBootApplicationpublic classSmsCodeStarter {public static voidmain(String[] args) {
SpringApplication.run(SmsCodeStarter.class, args);
}
}
4. ValidateCode.java
packagecom.java.validate.code;importjava.time.LocalDateTime;/*** 验证码封装类
*
*@authorLogan
**/
public classValidateCode {/*** 验证码*/
privateString code;/*** 过期时间*/
privateLocalDateTime expireTime;/*** 指定验证码和有效分钟数的构造方法
*
*@paramcode 验证码
*@paramvalidityMinutes 有效分钟数*/
public ValidateCode(String code, intvalidityMinutes) {this.code =code;this.expireTime =LocalDateTime.now().plusMinutes(validityMinutes);
}/*** 指定验证码和过期时间的构造方法
*
*@paramcode 验证码
*@paramexpireTime 过期时间*/
publicValidateCode(String code, LocalDateTime expireTime) {this.code =code;this.expireTime =expireTime;
}publicString getCode() {returncode;
}publicLocalDateTime getExpireTime() {returnexpireTime;
}
}
5. CodeGenerator.java
packagecom.java.validate.generator;importorg.apache.commons.lang3.RandomStringUtils;importcom.java.validate.code.ValidateCode;/*** 验证码生成器
*
*@authorLogan
**/
public classCodeGenerator {/*** 验证码生成方法
*
*@paramlength 验证码长度
*@paramvalidityMinutes 过期分钟数
*@return
*/
public static ValidateCode generate(int length, intvalidityMinutes) {
String code=RandomStringUtils.randomNumeric(length);return newValidateCode(code, validityMinutes);
}
}
6. ValidateCodeSender.java
packagecom.java.validate.sender;importjava.io.IOException;importjava.io.PrintWriter;importjavax.servlet.http.HttpServletResponse;importorg.springframework.stereotype.Component;/*** 验证码发送器
*
*@authorLogan
**/@Componentpublic classValidateCodeSender {/*** 模拟发送手机验证码,此处发回浏览器,实际情况根据短信服务商做调整
*
*@paramresponse HTTP响应对象
*@parammobile 手机号
*@paramcode 验证码*/
public voidsendSmsCode(HttpServletResponse response, String mobile, String code) {
System.out.println(String.format("模拟向手机号【%s】发送验证码【%s】", mobile, code));
write(response,"验证码为:" +code);
}/*** 发送HTTP响应信息
*
*@paramresponse HTTP响应对象
*@parammessage 信息内容*/
private voidwrite(HttpServletResponse response, String message) {
response.setContentType("text/html; charset=UTF-8");
PrintWriter writer= null;try{
writer=response.getWriter();
writer.write(message);
writer.flush();
}catch(IOException e) {
e.printStackTrace();
}finally{
writer.close();
}
}
}
7. ValidateCodeFilter.java
packagecom.java.validate.filter;importjava.io.IOException;importjava.io.PrintWriter;importjava.time.LocalDateTime;importjava.util.ArrayList;importjava.util.List;importjavax.servlet.FilterChain;importjavax.servlet.ServletException;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importorg.apache.commons.lang3.StringUtils;importorg.springframework.stereotype.Component;importorg.springframework.web.bind.ServletRequestBindingException;importorg.springframework.web.bind.ServletRequestUtils;importorg.springframework.web.filter.OncePerRequestFilter;importcom.java.controller.ValidateCodeController;importcom.java.validate.code.ValidateCode;/*** 校验验证码过滤器
*
*@authorLogan
* @createDate 2019-02-07
**/@Componentpublic class ValidateCodeFilter extendsOncePerRequestFilter {/*** 需要校验短信验证码的请求*/
private List smsCodeUrls = new ArrayList<>();
@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throwsServletException, IOException {/*** 如果需要校验短信验证码的请求集合中,包含当前请求,则进行短信验证码校验*/
if(smsCodeUrls.contains(request.getRequestURI())) {if(smsCodeValid(request, response)) {//校验通过,继续向后执行
filterChain.doFilter(request, response);
}
}//其它请求,直接放过
else{
filterChain.doFilter(request, response);
}
}
@Overrideprotected void initFilterBean() throwsServletException {//初始化添加需要校验的请求到集合中,可由配置文件中配置,此处为了简洁,直接添加
smsCodeUrls.add("/login/mobile");
}/*** 短信验证码是否有效