登录验证码开发记录
登录验证码开发记录
后台使用了Controller层选用了SpringMvc,验证码存储在Ehcache中并设置自动过期时间为1分钟,key值使用sessionId,验证码生成使用了kaptcha插件。
需求分析:
- 前台需要生成一个4位数的验证码图片
- 提交之后由后台判断验证码是否输入正确
- 验证码有效期为1分钟
思路分析:
- 在后台生成一个4位数的随机数字作为验证码值存入ehcache中,设置ehcache的过期时间为1分钟,key值为sessionId。将验证码值用kaptcha插件生成验证码图片,并返回到前台
- 用户输入验证码登录之后,在登录接口从ehcache根据sessionId获取验证码,如果为null,则表示验证码已过期,如果不等于前台传过来的验证码,则返回验证码错误,否则登录成功
前台代码:
<img class="authCode" ref="authCode" src="/login/authcode" @click.stop="getAuthCode" title="点击切换验证码">
<script>
getAuthCode: function () {
$(this.$refs.authCode).attr('src', '/login/authcode?' + Math.floor(Math.random() * 1000000));
}
</script>
当点击img标签时,重新获取验证码,后面跟上随机数防止页面缓存
后端获取验证码接口
@Autowired
private Producer kaptchaProducer;
@Autowired
private CacheManager cacheManager
@RequestMapping("/authcode")
public void authCode(HttpServletRequest request, HttpServletResponse response) {
response.setContentType("image/jpeg");
String capText = kaptchaProducer.createText();
Cache cache = cacheManager.getCache("authCode");
Element element = new Element(request.getRequestedSessionId(), capText);
cache.put(element);
BufferedImage bi = kaptchaProducer.createImage(capText);
ServletOutputStream out = null;
try {
out = response.getOutputStream();
out.flush();
ImageIO.write(bi, "jpg", out);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
后端登录接口:
@RequestMapping(value = "/authlogin")
public String authLogin(@Validated(LoginValidator.class) UserQuery query, HttpServletRequest request) {
Cache cache = cacheManager.getCache("authCode");
Element element = cache.get(request.getRequestedSessionId());
if (element == null) {
return "验证码已过期";
}
String authCode = element.getObjectValue().toString();
if (authCode.equalsIgnoreCase(query.getAuthCode())) {
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(query.getUsername(), query.getPassword());
subject.login(token);
return "ok";
} else {
cache.remove(request.getRequestedSessionId());
return "验证码错误";
}
}
kaptcha配置:
在resources目录下创建kaptcha.xml文件,用来配置验证码生成规则
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
<!-- Kaptcha组件配置 -->
<bean id="kaptchaProducer" class="com.google.code.kaptcha.impl.DefaultKaptcha">
<property name="config">
<bean class="com.google.code.kaptcha.util.Config">
<constructor-arg>
<props>
<!-- 验证码宽度 -->
<prop key="kaptcha.image.width">120</prop>
<!-- 验证码高度 -->
<prop key="kaptcha.image.height">50</prop>
<!-- 生成验证码内容范围 -->
<prop key="kaptcha.textproducer.char.string">3457acdefhkmnprstuvwxyACDEFGHKLMNPQRSTUVWXY</prop>
<!-- 验证码个数 -->
<prop key="kaptcha.textproducer.char.length">4</prop>
<!-- 是否有边框 -->
<prop key="kaptcha.border">no</prop>
<!-- 边框颜色 -->
<prop key="kaptcha.border.color">105,179,90</prop>
<!-- 边框厚度 -->
<prop key="kaptcha.border.thickness">1</prop>
<!-- 验证码字体颜色 -->
<prop key="kaptcha.textproducer.font.color">yellow</prop>
<!-- 验证码字体大小 -->
<prop key="kaptcha.textproducer.font.size">30</prop>
<!-- 验证码所属字体样式 -->
<prop key="kaptcha.textproducer.font.names">楷体</prop>
<!-- 干扰线颜色 -->
<prop key="kaptcha.noise.color">black</prop>
<!-- 验证码文本字符间距 -->
<prop key="kaptcha.textproducer.char.space">8</prop>
<!-- 图片样式 :阴影-->
<prop key="kaptcha.obscurificator.impl">com.google.code.kaptcha.impl.ShadowGimpy</prop>
<!-- 去除干扰线 -->
<prop key="kaptcha.noise.impl">com.google.code.kaptcha.impl.NoNoise</prop>
</props>
</constructor-arg>
</bean>
</property>
</bean>
</beans>
Spring Boot验证码配置类
@Configuration
@ImportResource(locations = "classpath:kaptcha.xml")
public class CaptchaConfig {
}
Ehcache相关配置:
在resources目录配置ehcache.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
updateCheck="false">
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="300"
overflowToDisk="false"
diskPersistent="false"
/>
<cache name="authCode"
maxEntriesLocalHeap="0"
eternal="false"
timeToIdleSeconds="60"
timeToLiveSeconds="60"
overflowToDisk="false"
statistics="true">
</cache>
</ehcache>
application.yml
spring:
cache:
ehcache:
config: classpath:ehcache.xml
pom.xml依赖
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>2.3.2</version>
</dependency>
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>2.3.2</version>
</dependency>
效果图