图形验证码及其重构
Posted fly-book
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了图形验证码及其重构相关的知识,希望对你有一定的参考价值。
图形验证码
<!--验证码组件-->
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>2.3.2</version>
</dependency>
定义验证码
public class ImageCode {
private String code;
//有效期
private LocalDateTime expireTime;
private BufferedImage image;
public ImageCode(String code, int expireTime, BufferedImage image) {
this.code = code;
this.expireTime = LocalDateTime.now().plusSeconds(expireTime);
this.image = image;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public LocalDateTime getExpireTime() {
return expireTime;
}
public void setExpireTime(LocalDateTime expireTime) {
this.expireTime = expireTime;
}
public BufferedImage getImage() {
return image;
}
public void setImage(BufferedImage image) {
this.image = image;
}
public boolean isExpried() {
return LocalDateTime.now().isAfter(expireTime);
}
}
请求的验证码会保存到session中
@RestController
public class ValidateCodeController {
public static final String SESSION_KEY = "captcha";
@Autowired
private Producer captchaProducer;
@Bean
public Producer captcha(){
Properties properties = new Properties();
properties.setProperty("kaptcha.image.width","150");
properties.setProperty("kaptcha.image.height","150");
//字符集
properties.setProperty("kaptcha.textproducer.char.string","0123456789");
//字符长度
properties.setProperty("kaptcha.textproducer.char.length","4");
Config config = new Config(properties);
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
defaultKaptcha.setConfig(config);
return defaultKaptcha;
}
@GetMapping("/captcha")
public void getCaptcha(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.setContentType("image/jpeg");
String capText = captchaProducer.createText();
BufferedImage bi = captchaProducer.createImage(capText);
ImageCode imageCode = new ImageCode(capText,60,bi);
request.getSession().setAttribute(SESSION_KEY,imageCode);
ServletOutputStream out = response.getOutputStream();
ImageIO.write(bi,"jpg",out);
try {
out.flush();
} finally {
out.close();
}
}
}
/**
* 验证码异常
*/
public class VerificationCodeException extends AuthenticationException {
public VerificationCodeException(String msg) {
super(msg);
}
}
验证过滤器
public class ValidateCodeFilter extends OncePerRequestFilter {
public ValidateCodeFilter(AuthenticationFailureHandler flyAuthenticationFailureHandler) {
this.flyAuthenticationFailureHandler = flyAuthenticationFailureHandler;
}
private AuthenticationFailureHandler flyAuthenticationFailureHandler;
public AuthenticationFailureHandler getFlyAuthenticationFailureHandler() {
return flyAuthenticationFailureHandler;
}
public void setFlyAuthenticationFailureHandler(AuthenticationFailureHandler flyAuthenticationFailureHandler) {
this.flyAuthenticationFailureHandler = flyAuthenticationFailureHandler;
}
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
if ("/authentication/form".equals(httpServletRequest.getRequestURI())
&&"post".equalsIgnoreCase(httpServletRequest.getMethod())){
try {
validate(httpServletRequest);
}catch (VerificationCodeException e){
flyAuthenticationFailureHandler.onAuthenticationFailure(httpServletRequest,httpServletResponse,e);
return;
}
}
filterChain.doFilter(httpServletRequest,httpServletResponse);
}
private void validate(HttpServletRequest request) {
HttpSession session = request.getSession();
ImageCode codeInSession = (ImageCode) session.getAttribute(ValidateCodeController.SESSION_KEY);
String imageCode = request.getParameter("imageCode");
if (StringUtils.isEmpty(imageCode)){
throw new VerificationCodeException("验证码的值不能为空");
}
if (codeInSession==null){
throw new VerificationCodeException("验证码不存在");
}
if (codeInSession.isExpried()){
session.removeAttribute(ValidateCodeController.SESSION_KEY);
throw new VerificationCodeException("验证码已过期");
}
if (!imageCode.equals(codeInSession.getCode())){
throw new VerificationCodeException("验证码不匹配");
}
session.removeAttribute(ValidateCodeController.SESSION_KEY);
}
}
将验证码过滤加到UsernamePasswordAuthenticationFilter前面,将图片验证码请求允许访问
@Override
protected void configure(HttpSecurity http) throws Exception {
ValidateCodeFilter codeFilter = new ValidateCodeFilter(flyAuthenticationFailureHandler);
http
.addFilterBefore(codeFilter, UsernamePasswordAuthenticationFilter.class)
.formLogin()
.loginPage("/authentication/request")
.loginProcessingUrl("/authentication/form")
.successHandler(flyAuthenticationSuccessHandler)
.failureHandler(flyAuthenticationFailureHandler)
.and()
.authorizeRequests()
.antMatchers("/authentication/request",
securityProperties.getBrowser().getLoginPage(),
"/captcha")
.permitAll()
.anyRequest().authenticated()
.and().csrf().disable();
}
开始login吧
<form action="/authentication/form" method="post">
用户名: <input type="text" name="username"><br>
密码: <input type="password" name="password"><br>
验证码:<input type="text" name="imageCode"><img src="/captcha">
<input type="submit">
</form>
图形验证码重构
public interface ValidateCodeGenerator {
ImageCode generate(HttpServletRequest request);
}
public class ImageCodeGenerator implements ValidateCodeGenerator {
@Autowired
private SecurityProperties securityProperties;
public void setSecurityProperties(SecurityProperties securityProperties) {
this.securityProperties = securityProperties;
}
private Producer captcha(){
Properties properties = new Properties();
properties.setProperty("kaptcha.image.width",String.valueOf(securityProperties.getCode().getImageCode().getWidth()));
properties.setProperty("kaptcha.image.height",String.valueOf(securityProperties.getCode().getImageCode().getHeight()));
//字符集
properties.setProperty("kaptcha.textproducer.char.string","0123456789");
//字符长度
properties.setProperty("kaptcha.textproducer.char.length",String.valueOf(securityProperties.getCode().getImageCode().getLength()));
Config config = new Config(properties);
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
defaultKaptcha.setConfig(config);
return defaultKaptcha;
}
@Override
public ImageCode generate(HttpServletRequest request) {
Producer captchaProducer = captcha();
String capText = captchaProducer.createText();
BufferedImage bi = captchaProducer.createImage(capText);
return new ImageCode(capText,securityProperties.getCode().getImageCode().getExpireIn(),bi);
}
}
只需创建继承ValidateCodeGenerator的imageValidateCodeGenerator的bean就可以覆盖实现方法
@Configuration
public class ValidateCodeBeanConfig {
@Autowired
private SecurityProperties securityProperties;
@Bean
@ConditionalOnMissingBean(name = "imageValidateCodeGenerator")
public ValidateCodeGenerator imageValidateCodeGenerator(){
ImageCodeGenerator codeGenerator = new ImageCodeGenerator();
codeGenerator.setSecurityProperties(securityProperties);
return codeGenerator;
}
}
@RestController
public class ValidateCodeController {
public static final String SESSION_KEY = "captcha";
@Autowired
private ValidateCodeGenerator imageCodeGenerator;
@GetMapping("/captcha")
public void getCaptcha(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.setContentType("image/jpeg");
ImageCode imageCode = imageCodeGenerator.generate(request);
request.getSession().setAttribute(SESSION_KEY,imageCode);
ServletOutputStream out = response.getOutputStream();
ImageIO.write(imageCode.getImage(),"jpg",out);
try {
out.flush();
} finally {
out.close();
}
}
}
用户自己实现
@Component("imageValidateCodeGenerator")
public class MyImageValidateCodeGenerator implements ValidateCodeGenerator {
public ImageCode generate(HttpServletRequest request) {
System.out.println("图形验证码实现");
//。。。
return null;
}
}
以上是关于图形验证码及其重构的主要内容,如果未能解决你的问题,请参考以下文章