登录验证码开发记录

登录验证码开发记录

后台使用了Controller层选用了SpringMvc,验证码存储在Ehcache中并设置自动过期时间为1分钟,key值使用sessionId,验证码生成使用了kaptcha插件。

需求分析:

  1. 前台需要生成一个4位数的验证码图片
  2. 提交之后由后台判断验证码是否输入正确
  3. 验证码有效期为1分钟

思路分析:

  1. 在后台生成一个4位数的随机数字作为验证码值存入ehcache中,设置ehcache的过期时间为1分钟,key值为sessionId。将验证码值用kaptcha插件生成验证码图片,并返回到前台
  2. 用户输入验证码登录之后,在登录接口从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>

效果图
image.png

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×