网站验证码的设计与实现

本文涉及的产品
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

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

相关文章
|
消息中间件 Linux API
C/C++ 进程间通信system V IPC对象超详细讲解(系统性学习day9)
C/C++ 进程间通信system V IPC对象超详细讲解(系统性学习day9)
|
网络安全 开发工具
SSH断开连接时长控制ServerAliveInterval
SSH断开连接时长控制ServerAliveInterval
787 0
|
3月前
|
SQL 人工智能 数据挖掘
Apache Flink:从实时数据分析到实时AI
Apache Flink 是实时数据处理领域的核心技术,历经十年发展,已从学术项目成长为实时计算的事实标准。它在现代数据架构中发挥着关键作用,支持实时数据分析、湖仓集成及实时 AI 应用。随着 Flink 2.0 的发布,其在流式湖仓、AI 驱动决策等方面展现出强大潜力,正推动企业迈向智能化、实时化的新阶段。
494 9
Apache Flink:从实时数据分析到实时AI
|
9月前
|
机器学习/深度学习 存储 算法
DeepSeek元学习(Meta-Learning)基础与实践
元学习(Meta-Learning),又称“学会学习”,旨在通过少量数据或训练步骤使模型快速适应新任务。本文介绍如何使用DeepSeek构建和训练元学习模型,重点讲解基于优化的元学习方法MAML。我们从定义任务生成器、实现MAML算法到训练模型和快速适应新任务,提供了详细的代码示例和常见问题解决方案。通过本文,读者可以掌握元学习的基础与实践技巧,利用DeepSeek高效构建元学习模型。
|
8月前
|
XML JSON Linux
Reqable:跨平台HTTP开发与调试工具
Reqable是一款功能强大且易于使用的跨平台HTTP开发与调试工具,具有多平台支持、全面的HTTP请求构建与解析、请求历史记录和环境管理等功能。它简化了HTTP请求的构建、发送和响应分析过程,为开发者提供了极大的便利。通过Reqable,开发者可以更高效地进行HTTP开发和调试,提高工作效率和代码质量。
676 26
|
JSON 缓存 前端开发
PHP如何高效地处理JSON数据:从编码到解码
在现代Web开发中,JSON已成为数据交换的标准格式。本文探讨了PHP如何高效处理JSON数据,包括编码和解码的过程。通过简化数据结构、使用优化选项、缓存机制及合理设置解码参数等方法,可以显著提升JSON处理的性能,确保系统快速稳定运行。
|
XML Java 数据格式
如何使用 Spring Cloud 实现网关
如何使用 Spring Cloud 实现网关
335 3
|
开发者 人工智能 自然语言处理
欢迎使用通义灵码
灵码使用指南!一键收藏。
142805 31
|
IDE API 开发工具
Gleam
Gleam 是面向 Erlang 虚拟机的类型化语言,Gleam 的语法对于类型化语言来说非常优雅和简单。如果能看到 Gleam 像 Elixir 一样成功,那就太酷了。
694 4
|
分布式计算 Java 持续交付
如何选择合适的微服务框架
如何选择合适的微服务框架
305 0