DDR爱好者之家 Design By 杰米

在介绍之前,首先一个概念明确一个共识:没有攻不破的网站,只有值不值得。

这意思是说,我们可以尽可能的提高自己网站的安全,但并没有绝对的安全,当网站安全级别大于攻击者能得到的回报时,你的网站就是安全的。

所以百度搜到的很多验证码都已经结合了人工智能分析用户行为,很厉害。但这里只介绍我的小网站是怎么设计的。

大概逻辑:当需要验证码时,前端发送ajax向后台请求相关数据发送回前端,由前端生成(与后端生成图片,然后传送图片到前端的做法相比安全性要差很多。但也是可以预防的,后端可以对此Session进行请求记录,如果在一定时间内恶意多次请求,可以进行封禁ip等对策),验证完成后,后台再对传回的数据进行校验。

效果图:

滑动验证码的设计与理解

滑动验证码的设计与理解

1|0js类的设计:

1.定义一个验证码父类,因为目前只有这一个验证类型,倘若以后再要扩展其他验证类型呢。那么它们之间肯定有很多公共之处(如:验证成功、失败的回调,获取验证码的类型,获取验证结果等),所以这些共同点可以提炼出来,下面是我目前的父类样子:

 

 /**
 * 验证码的父类,所有验证码都要继承这个类
 * @param id 验证码的唯一标识
 * @param type 验证码的类型
 * @param contentDiv 包含着验证码的DIV
 * @constructor
 */
 var Identifying = function (id,type,contentDiv){
  this.id = id;
  this.type = type;
  this.contentDiv=contentDiv;
 }
 /**
 * 销毁函数
 */
 Identifying.prototype.destroy = function(){
  this.successFunc = null;
  this.errorFunc = null;
  this.clearDom();
  this.contentDiv = null;
 }
 /**
 * 清除节点内容
 */
 Identifying.prototype.clearDom = function(){
  if(this.contentDiv instanceof jQuery){
   this.contentDiv.empty();
  }else if(this.contentDiv instanceof HTMLElement){
   this.contentDiv.innerText = "";
  }
 }
 /**
 * 回调函数
 * 验证成功后进行调用
 * this需要指具体验证类
 * @param result 对象,有对应验证类的传递的参数,具体要看验证类
 */
 Identifying.prototype.success = function (result) {
  if(this.successFunc instanceof Function){
   this.successFunc(result);
  }
 }
 /**
 * 验证失败发生错误调用的函数
 * @param result
 */
 Identifying.prototype.error = function (result) {
  if(this.errorFunc instanceof Function){
   this.errorFunc(result);
  }else{
   //统一处理错误
  }
 }
 /**
 * 获取验证码id
 */
 Identifying.prototype.getId = function () {
  return this.id;
 }
 /**
 * 获取验证码类型
 * @returns {*}
 */
 Identifying.prototype.getType = function () {
  return this.type;
 }
 /**
 * 显示验证框
 */
 Identifying.prototype.showIdentifying = function(callback){
  this.contentDiv.show(null,callback);
 }
 /**
 * 隐藏验证框
 */
 Identifying.prototype.hiddenIdentifying = function(callback){
  this.contentDiv.hide(null,callback);
 }
 /**
 * 获得验证码显示的dom元素
 */
 Identifying.prototype.getContentDiv = function () {
  return this.contentDiv;
 }

然后,滑动验证码类继承此父类(js继承会单独写篇文章),滑动验证码类如下:

  

 /**
 * 滑动验证类
 * complete传递的参数为identifyingId,identifyingType,moveEnd_X
 * @param config 各种配置
 */
 var ImgIdentifying = function(config) {
  Identifying.call(this, config.identifyingId, config.identifyingType,config.el);
  this.config = config;
  this.init();
  this.showIdentifying();
 }
 //继承父类
 extendClass(Identifying, ImgIdentifying);
 /**
 * 销毁函数
 */
 ImgIdentifying.prototype.destroy = function () {
  Identifying.prototype.destroy.call(this);
 }
 var width = '260';
 var height = '116';
 var pl_size = 48;
 var padding_ = 20;
 ImgIdentifying.prototype.init = function () {
  this.clearDom();
  var el = this.getContentDiv();
  var w = width;
  var h = height;
  var PL_Size = pl_size;
  var padding = padding_;
  var self = this;
  //这个要转移到后台
  function RandomNum(Min, Max) {
   var Range = Max - Min;
   var Rand = Math.random();
   if (Math.round(Rand * Range) == 0) {
    return Min + 1;
   } else if (Math.round(Rand * Max) == Max) {
    return Max - 1;
   } else {
    var num = Min + Math.round(Rand * Range) - 1;
    return num;
   }
  }
  //确定图片
  var imgSrc = this.config.img;
  var X = this.config.X;
  var Y = this.config.Y;
  var left_Num = -X + 10;
  var html = '<div style="position:relative;padding:16px 16px 28px;border:1px solid #ddd;background:#f2ece1;border-radius:16px;">';
  html += '<div style="position:relative;overflow:hidden;width:' + w + 'px;">';
  html += '<div style="position:relative;width:' + w + 'px;height:' + h + 'px;">';
  html += '<img id="scream" src="/UploadFiles/2021-04-02/' + imgSrc + '">

其中init的方法,大家就可以抄啦,验证码是这里生成的(感谢网上一些热心网友提供的Mod,在此基础上改的)。

2|0后端的设计:

首先要有一个验证码的接口,将一些常量和共同的方法抽象到接口中(接口最重要的作用就是行为的统一,意思是我如果知道这个是验证码,那么必定就会有验证的方法,不管它是滑动验证,图形验证等,然后就可以放心的调用验证方法去获取验证结果,下面过滤器设计就可以立马看到这作用。具体java接口的说明会单独写篇文章),接口如下:

 /**
 * 验证码类的接口,所有验证码必须继承此接口
 */
 public interface I_Identifying<T> {
  String EXCEPTION_CODE = SystemStaticValue.IDENTIFYING_EXCEPTION_CODE;
  String IDENTIFYING = "Identifying";
  //--------------以下为验证码大体错误类型,抛出错误时候用,会传至前端---------------
  //验证成功
  String SUCCESS = "Success";
  //验证失败
  String FAILURE = "Failure";
  //验证码过期
  String OVERDUE = "Overdue";
  //-------以下为验证码具体错误类型,存放在checkResult-------------
  String PARAM_ERROR = "验证码参数错误";
  String OVERDUE_ERROR = "验证码过期";
  String TYPE_ERROR = "验证码业务类型错误";
  String ID_ERROR = "验证码id异常";
  String CHECK_ERROR = "验证码验证异常";
  /**
  * 获取生成好的验证码
  * @param request
  * @return
  */
  public T getInstance(HttpServletRequest request) throws Exception;
  /**
  * 进行验证,没抛异常说明验证无误
  * @return
  */
  public void checkIdentifying(HttpServletRequest request) throws Exception;
  /**
  * 获取验证结果,如果成功则为success,失败则为失败信息
  * @return
  */
  public String getCheckResult();
  /**
  * 获取验证码的业务类型
  * @return
  */
  public String getIdentifyingType();
 }

然后,设计一个具体的滑动验证类去实现这个接口,这里只贴参数:

 /**
 * @author NiceBin
 * @description: 验证码类,前端需要生成验证码的信息
 * @date 2019/7/12 16:04
 */
 public class ImgIdentifying implements I_Identifying<ImgIdentifying>,Serializable {
  //此次验证码的id
  private String identifyingId;
  //此次验证码的业务类型
  private String identifyingType;
  //需要使用的图片
  private String imgSrc;
  //生成块的x坐标
  private int X;
  //生成块的y坐标
  private int Y;
  //允许的误差
  private int deviation = 2;
  //验证码生成的时间
  private Calendar calendar;
  //验证码结果,如果有结果说明已经被校验,防止因为网络延时的二次校验
  private String checkResult;
 
  //下面是逻辑代码...
 }

上面每个变量都是一种校验手段,如calendar可以检验验证码是否过期,identifyingType检验此验证码是否是对应的业务等。每多想一点,别人破解就多费劲一点。

后端验证码的验证是不需要具体的类去调用的,而是被一个过滤器统一过滤,才过滤器注册的时候,将需要进行验证的路径写进去即可,过滤器代码如下:

r NiceBin
 * @description: 验证码过滤器,帮忙验证有需要验证码的请求,不帮忙生成验证码
 * @date 2019/7/23 15:06
 */
 @Component
 public class IdentifyingInterceptor implements HandlerInterceptor {
  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
   HttpSession session = request.getSession();
   I_Identifying identifying= (I_Identifying)session.getAttribute(I_Identifying.IDENTIFYING);
   if(identifying!=null){
    identifying.checkIdentifying(request);
   }else {
    //应该携带验证码信息的,结果没有携带,那就是个非法请求
    return false;
   }
   return true;
  }
  @Override
  public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
  }
  @Override
  public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
  }
 }

可以看到接口的用处了,之前在用户申请验证码时,验证码类是放到用户session中的,所以这里直接取出调用checkIdentifying即可,不需要关系它到底是滑动验证码,还是图片验证码什么的。

总结

以上所述是小编给大家介绍的滑动验证码的设计与理解,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

DDR爱好者之家 Design By 杰米
广告合作:本站广告合作请联系QQ:858582 申请时备注:广告合作(否则不回)
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
DDR爱好者之家 Design By 杰米

稳了!魔兽国服回归的3条重磅消息!官宣时间再确认!

昨天有一位朋友在大神群里分享,自己亚服账号被封号之后居然弹出了国服的封号信息对话框。

这里面让他访问的是一个国服的战网网址,com.cn和后面的zh都非常明白地表明这就是国服战网。

而他在复制这个网址并且进行登录之后,确实是网易的网址,也就是我们熟悉的停服之后国服发布的暴雪游戏产品运营到期开放退款的说明。这是一件比较奇怪的事情,因为以前都没有出现这样的情况,现在突然提示跳转到国服战网的网址,是不是说明了简体中文客户端已经开始进行更新了呢?