网站验证码的设计与实现

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: 网站验证码的设计与实现

前言


在平时,有一些网站会有很多处需要验证码验证的地方,遂今天研究验证码的验证方法,为了是验证码的代码,一次编写,到处运行,而且还得是实现可配置的操作。


正文


一:java注解的基本操作


    实现可插拔,最主要的是注解,因为注解可以降低代码的入侵性,只需要配置注解,就可以实现不同的功能


二:spring的拦截器的基本操作


      可以这样想象,在一个提供的接口前,如果把所有的验证码都利用拦截器来进行处理,那么就实现了一次编写到处使用,而且我们在编写的过程中不必纠结于验证码的操作,是我们的开发工作能更好的专注于我们的业务,以及业务的逻辑,那么我们的开发的效率会大大提高。


三:综上所述,我们要这样设计我们的网站验证码的统一操纵:


首先:我们要定义这个的一个注解;

package com.breakpoint.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * 接口防刷限流注解方式
 *
 * @author :breakpoint/赵立刚
 * @date : 2018/04/02
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AccessLimit {
    /**
     * 两次点击间隔时间  默认时间1000ms  单位ms
     *
     * @return
     */
    long interval() default 1000L;
    /**
     * 是否需要进行登录
     *
     * @return
     */
    boolean isLogIn() default true;
    /**
     * 冻结的账户是否可以进行通过   必须是 isLogIn 为true的情况下才有效
     *
     * @return
     */
    boolean freezeCanAccess() default false;
    /**
     * 该接口是否可用  也可以说接口是否可达
     *
     * @return
     */
    boolean enable() default true;
    /**
     * 验证码是否需要进行验证
     *
     * @return
     */
    boolean isVerifyCode() default false;
    /**
     * 权限值  大于等于才能进行操作
     * <p>
     * 当然 首先得闲登陆
     *
     * @return
     */
    int permissionInt() default 0;
}

其次:我们要定义一个Interceptor

package com.breakpoint.configue;
import com.breakpoint.annotation.AccessLimit;
import com.breakpoint.constans.RetCodeConstant;
import com.breakpoint.util.ExploreWriteUtils;
import com.breakpoint.util.TokenUtils;
import com.breakpoint.util.UserInfo;
import com.redis.RedisSetObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * 检验用户登陆以及其他操作
 * Created by Administrator on 2018/4/29 0029.
 */
@Slf4j
public class AccessLimitInterceptor extends HandlerInterceptorAdapter {
    private RedisTemplate redisTemplate;
    public AccessLimitInterceptor(RedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }
    /**
     * 限流防止频繁刷新
     *
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        if (handler instanceof HandlerMethod) {
            /**
             * 向下强转
             */
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            AccessLimit methodAnnotation = handlerMethod.getMethodAnnotation(AccessLimit.class);//获取到我们的那个注解,之后根据我们的配置,来进行是否操作
            if (null != methodAnnotation) {
                /**
                 * 具体的操作逻辑
                 */
                ValueOperations valueOperations = redisTemplate.opsForValue();
                /**
                 * 验证验证码是否正确
                 */
                if (methodAnnotation.isVerifyCode()) {
                    /**
                     * 首先verifyCode存储在redis
                     *
                     */
                    String key = request.getParameter("verifyCodeKey");
                    if (StringUtils.isEmpty(key)) {
                        ExploreWriteUtils.writeMessage(RetCodeConstant.FAIL, request, response,
                                "请求参数中没有verifyCodeKey");
                        return false;
                    }
                    /**
                     * 获取到存储的key
                     */
                    String verifyCodeKey = RedisSetObject.getKey(key);
                    /**
                     * 验证码的基本操作 1min 时间
                     */
                    String verifyCode = (String) valueOperations.get(verifyCodeKey);
                    if (StringUtils.isEmpty(verifyCode)) {
                        ExploreWriteUtils.writeMessage(RetCodeConstant.ALERT, request, response,
                                "请刷新验证码");
                        return false;
                    }
                    /**
                     * 提交过来的验证码
                     */
                    String verifyCode1 = request.getParameter("verifyCode");
                    if (StringUtils.isEmpty(verifyCode1)) {
                        ExploreWriteUtils.writeMessage(RetCodeConstant.FAIL, request, response,
                                "请填写验证码");
                        return false;
                    }
                    /**
                     * 检验验证码是否一直
                     */
                    String verifyCodeRedis = verifyCode.toLowerCase().trim();
                    String verifyCodeReq = verifyCode1.toLowerCase().trim();
                    log.info(verifyCode);
                    log.info(verifyCodeRedis);
                    log.info(verifyCodeReq);
                    if (!verifyCodeRedis.equals(verifyCodeReq)) {
                        ExploreWriteUtils.writeMessage(RetCodeConstant.FAIL, request, response,
                                "验证码不正确");
                        return false;
                    }
                }
            }
        }
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        if (response.getStatus() == 500) {
            modelAndView.setViewName("/errorpage/500");
        } else if (response.getStatus() == 404) {
            modelAndView.setViewName("404");
        }
        super.postHandle(request, response, handler, modelAndView);
    }
}

之后,我们在请求的时候的请求的数据,

$("#inner_liuyan_button").click(function () {
    addLoading($("#header_inner_show"));
    var message = $("#inner_liuyan_message").val();
    if(message.length<5||message.length>300){
        alert("输入的留言留言信息5到300字");
        completeLoading();
        return;
    }
    var postData = {
        message: message,
        verifyCodeKey:localStorage.getItem("verifyCodeKey"),//y验证码的取值的key
        verifyCode:$("#inner_liuyan_verifyCode").val()//用户提交的验证码
    };
    /**
     * 请求的基本操作
     */
    $.post("v1/liuyan/save", postData, function (returnData) {
        completeLoading();
        if(returnData.respCode==200){
            alert("发表成功");
            window.location.reload();
        }else {
            alert(returnData.data);
        }
    });
});
Controller方面的基本配置
/**
 * 新增加 留言信息
 *
 * @return
 */
@AccessLimit(isLogIn = false,isVerifyCode = true)//配置注解的基本操作,校验是否需要登陆位false,是否校验验证码为true
@PostMapping("/save")
public Object saveTopic(@RequestParam("message") String message, HttpServletRequest request) {
    try {
        String userName = request.getRemoteAddr();
        Object insert = liuYanService.insert(userName, message);
        return ResponseResult.createOK(insert);
    } catch (Exception e) {
        return ResponseResult.createFailResult("操作失败", e.getMessage());
    }
}

根据以上步骤,我们就配置好了如何进行校验验证码的整体的流,这样整体上,下次在需要使用校验验证码的时候仅仅使用注解

@AccessLimit(isLogIn = false,isVerifyCode = true)//配置注解的基本操作,校验是否需要登陆位false,是否校验验证码为true

加上前台请求的具体的请求格式即可,这样我们才能更加专注的编写我们自己项目的业务代码逻辑,节约更多的时间

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
安全 Java API
阿里云——Java实现手机短信验证码功能
通过手机短信发送验证码,是最普遍、最安全验证用户真实身份的方式。目前,短信验证码广泛应用于用户注册、密码找回、登录保护、身份认证、随机密码、交易确认等应用场景。本文通过调用API开发一个短信验证码为例,带您了解如何实现短信验证码功能。
5677 5
阿里云——Java实现手机短信验证码功能
|
7月前
|
安全 PHP 开发工具
注册登录首选,趣味滑块验证码
注册登录账户时,保障账户安全是首要任务!使用趣味滑块验证码,既能有效防御恶意攻击,又能为验证过程增添一丝乐趣。让注册和登录变得更加有趣又安全!
|
8月前
|
安全 机器人 PHP
在线行为验证码推荐
想要保护您的网站免受恶意攻击?不妨考虑一款免费行为验证插件。该插件基于用户的行为模式进行验证,可有效区分真实用户和机器人。其中,滑动拼图是一种常见的在线行为验证方式,能够增加验证的难度,提高网站的安全性。通过使用这款免费插件,您可以为您的网站添加一道可靠的安全防线。
|
运维 机器人 API
细数验证码的N种生成方式
验证码(CAPTCHA)是一种用于确定网站或应用程序使用者是否为人类的技术。它通常由一组图像或数字组成,用户需要输入正确的内容才能通过验证。验证码被广泛用于防止自动化脚本或机器人攻击,以确保用户是真正的人类。
352 0
细数验证码的N种生成方式
|
安全 前端开发 定位技术
推荐一个非常好的行为验证码项目!
KgCaptcha 结合了设备指纹、行为特征、访问频率、地理位置等多项技术,有效的拦截恶意登录、批量注册,阻断机器操作,拦截非正常用户。较传统验证码相比,用户无需再经过思考或输入操作,只需轻轻一滑即可进行验证。
推荐一个非常好的行为验证码项目!
|
安全 Java 黑灰产治理
注册中验证码实现(项目案例)
今天,给大家介绍验证码的相关配置问题。众所周知,对传统验证码而言,便捷和安全长期以来一直是鱼与熊掌的关系。这可从12306与黄牛的博弈中看出端倪。
注册中验证码实现(项目案例)
|
JavaScript 前端开发
简单的验证码功能
简单的验证码功能
简单的验证码功能
|
Java BI Maven
学会这个工具的使用,让你快速生成验证码
前言 验证码是我们做人机验证最常用的方式,常用于敏感操作的验证,比如:登录、注册、修改等。 验证码的原理:不同的客户端拥有不同的 session 对象,在看到验证码图片的时刻,服务器后端代码生成图片并将随机字符存储到 session 中。
1189 0