使用邮箱找回密码(二)验证码的时效性

使用邮箱找回密码(下)验证码的时效性

前面的Email类基本上算是成功了,测试也比较简单,前端加个按钮,后面自主给值就完了,测试一下,如果发送成功就行了,不成功的话就打断点调试,看运行过程中的参数的变化,本来就不是特别严谨的程序,不用扣太细,运行出来就好了。
邮箱的任务搞定了,那还有验证码呢?
这个就更简单了。
先定义一个verificationCode出来,用来存放和拼接字符串的

string VerificationCode = "";

然后搞一个字符串,走起。

string AllVerificationCode = "0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,G,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z";

来个区分大小写的(特殊字符的话感觉有点乱)这字符串一共是多少个字符?无所谓,反正看起来是挺多的哈,而且不重复,这就足够了。
这个是不是也可以用ASCII码加循环拼一个?百度一下

public static string Chr(int asciiCode)
  {
   if (asciiCode >= 0 && asciiCode <= 255)
   {
    System.Text.ASCIIEncoding asciiEncoding = new System.Text.ASCIIEncoding();
    byte[] byteArray = new byte[] { (byte)asciiCode };
    string strCharacter = asciiEncoding.GetString(byteArray);
    return (strCharacter);
   }
   else
   {
    throw new Exception("ASCII Code is not valid.");
   }
  }

我去,过于复杂了吧,还是手写比较快。

 string[] ArrayVerificationCode = AllVerificationCode.Split(',');

那现在字符串已经都搞定了,利用逗号,再给它拆开,使用字符串的分解方法split()

Random SingleVerificationCode = new Random();

然后random初始化,整几个随机数作为这个字符数组的下标,这样就完美的搞定了验证码的随机性质。

for (int i = 0; i < 24; i++)
{
    int Array_subscript = SingleVerificationCode.Next(ArrayVerificationCode.Length);
   VerificationCode = VerificationCode + ArrayVerificationCode[Array_subscript];
}

哎,ok。嗯?不对,这个VerificationCode = VerificationCode + ArrayVerificationCode[Array_subscript];不严谨了。

要迅捷。–提莫队长

正好,我恰巧知道这个更加迅捷的方式(也没有那么迅捷的说),就是加号和StringBuilder之间的区别,推荐一下

沉默的王二

,给个链接http://www.itwanger.com/java/2019/11/08/java-string-join.html
来,既然有别的换一下,换换口味嘛,想起来就顺手加深一遍印象了呗

		StringBuilder VerificationCode = new StringBuilder();
        string AllVerificationCode = "0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,G,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z";
        string[] ArrayVerificationCode = AllVerificationCode.Split(',');
        Random SingleVerificationCode = new Random();
        for (int i = 0; i < 24; i++)
        {
            int Array_subscript = SingleVerificationCode.Next(ArrayVerificationCode.Length);
            VerificationCode = VerificationCode.Append(ArrayVerificationCode[Array_subscript]);
        }

嗯,好了,加个大括号,方法名

public string GenerateVerificationCode()
    {
        StringBuilder VerificationCode = new StringBuilder();
        string AllVerificationCode = "0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,G,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z";
        string[] ArrayVerificationCode = AllVerificationCode.Split(',');
        Random SingleVerificationCode = new Random();
        for (int i = 0; i < 24; i++)
        {
            int Array_subscript = SingleVerificationCode.Next(ArrayVerificationCode.Length);
            VerificationCode = VerificationCode.Append(ArrayVerificationCode[Array_subscript]);
        }
        return VerificationCode.toString();
    }

Ok,大功告成。这样方法就可以直接返回一个随机的验证码了…
嗯?等等,验证码怎么保存呢?因为需要进行对比,所以验证码需要保存。
等等,等等,我觉得还是有很多问题得搞一下啊。
验证码怎么保存?如果保存完第一个验证码,我再申请一个验证码,那第一个还可以使用吗?如果可以使用的话,那验证码肯定是有时效的,这个时效怎么搞?
问题不少,慢慢来,先搞一个
验证码怎么保存。验证码肯定是需要保存的,当程序给用户发送验证码邮件的同时,需要保存发送的验证码然后和用户输入的验证码进行对比才行,那么保存到哪里呢?几个想法,

  1. 保存到数据库,单独找一个字段,比如用户信息表中,整一个不用的字段,存一下就完了。
  2. 保存到页面,session或者全局变量感觉都没问题啊。
    好了,保存到页面,可以少写点sql语句,嘿嘿。
    接下来就是验证码的时效性,也就是设置接收的验证码不分前后,只要是在时效范围内,都可以进行验证,嗯,合情合理,没啥毛病。
    哎呀,这才突然想起来这不是属性吗,时效性作为验证码的属性,ok,另起炉灶。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

public class VerificationCode
{
    public VerificationCode()
    {
    } 
}

接下来,就需要想一下关于验证码还需要什么属性了。
首先,这是一个验证码肯定是需要一个VerificationCode

public string Verificationcode { set; get; }

然后,为了体现时效性,那我们就得给一个有效时间

private TimeSpan EffectiveTime { set; get; }

这个TimeSpan类型,

表示的时间跨度也就是间隔,当然,这时候也需要一个有关于它的赋值,不然没有值,那就基本上算是没有意义的属性了。

EffectiveTime = TimeSpan.FromMinutes(2d);

这个就是赋值,FROM后面的英文是second就是秒,是minutes就是分钟,而参数是浮点型double类型的参数所以写为2d。
好了,时效性体现出来了,但是怎么确定验证码是不是在时效范文内呢?
这时候就需要创建时间CreateTime来确定了。

private DateTime CreateTime { set; get; }

然后就是判断是否有效的问题了,这个也可以作为验证码的属性,记作

public Boolean isEffective{ set; get; }

因为创建时间或者是有效时间都是对于用户来说没有意义的,所以,它们都是private,但是isEffective作为判断验证码是否过期的一个依据来说的话,必须能够get到其内容,但是不能随意set,也就是属性作为只读属性

问题来了,只读属性只看见过,没有自己写过啊。来着,上法宝!
百度救我。
……
Ok,问题解决,其实本身的方法体中的set;get;这种写法只是一种简写,set和get是属性的方法,在set前加一个private,让set方法不可使用

public Boolean isEffective{ private set; get; }

嗯,只读属性搞定。

那么,接下来就是赋值的时间了。属性已经搞定了,那么赋值呢?这里面四个属性,两个是私有的,还有一个是只读的,赋值怎么办?当然好办,差点忘记构造函数了,我们通过无参构造函数将函数在初始化定义前,给予其属性相应的值,就可以做到,在类定义后可以获得相应的参数。

public VerificationCode()
    {
        //创建的同时对创建时间和有效时间进行赋值        
		CreateTime = DateTime.Now;
        EffectiveTime = TimeSpan.FromMinutes(2d);
    }

Ok,赋值完成了。这样我们在创建VerificationCode这个对象的时候就可以直接获取到创建时间和有效时间了,这时候问题就来了isEffective这个属性的赋值方法是私有的,也就是不能直接赋值,那么,怎么给它赋值并且保证给它的值会随着时间进行变化?

不太明白,百度,走起。

百度就是知识宝库啊,总结了一下类的创建,可以直接写在get和set方法里面

 	//是否有效,不可赋值可以获取
    private Boolean _isEffective;
    public Boolean isEffective
    {
         private set
        {
            _isEffective = value;
        }
        get
        {
			return _isEffective;
		}
	}

Ok,这就可以了,说一下,这个简单说就是a,b,c赋值的问题,由一个中间变量搞定两个变量之间的数据交换。

还差一点,判断方法得写到get方法中,也就是说,在获取isEffective,也就是执行get方法时,获取当前时间然后减去创建时间和有效时间进行对比,如果小于有效时间表示在有效范文内,如果大于就是失效的验证码了。

private Boolean _isEffective;
    public Boolean isEffective
    {
        private set
        {
            _isEffective = value;
        }
        get
        {
            TimeSpan ts = DateTime.Now.Subtract(this.CreateTime);
            if (this.EffectiveTime <= ts)
            {
                this._isEffective = false;
            }
            else
            {
                this._isEffective = true;
            }
            return _isEffective;
        }
    }

这里有一个简单的小点,就是时间的加减。因为定义的创建时间是DateTime类型的,减法就是subtract(),得到的也是一个时间间隔类型(TimeSpan)的结果。

这样,整个的验证码类就搞定了。

前面我写了两个验证码的保存方法,我决定使用全局变量的方法,当然全局变量保存就要求页面不能随意刷新,所以,前端设计需要包含ScriptManagerUpdatePanel用以局部刷新,保证全局变量不会被刷新清空。定义一个list,保存验证码。

private static List<VerificationCode> vclist = new List<VerificationCode>();

验证一下,上面的获取方法也需要变更一下了。

/// <summary>
    /// 生成一个随机的验证码
    /// </summary>
    /// <returns></returns>
    public VerificationCode GenerateVerificationCode()
    {
        StringBuilder VerificationCode = new StringBuilder();
        string AllVerificationCode = "0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,G,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z";
        string[] ArrayVerificationCode = AllVerificationCode.Split(',');
        Random SingleVerificationCode = new Random();
        for (int i = 0; i < 24; i++)
        {
            int Array_subscript = SingleVerificationCode.Next(ArrayVerificationCode.Length);
            VerificationCode = VerificationCode.Append(ArrayVerificationCode[Array_subscript]);
        }
        VerificationCode vc = new VerificationCode();
        vc.Verificationcode = VerificationCode.ToString();
        vclist.Add(vc);
        return vc;
	}

写一个循环先判断验证码能不能匹配,如果不能就说明验证码本身就是不对的,如果匹配上了,就可以看验证码本身的isEffective是否过期。
Ok,上代码。
这个是VerificationCode

/// <summary>
/// 生成一个验证码对象
/// </summary>
public class VerificationCode
{
    //验证码 可以获取以及赋值
    public string Verificationcode { set; get; }
    //创建时间 不可赋值和获取
    private DateTime CreateTime { set; get; }
    //有效时间 不可赋值和获取
    private TimeSpan EffectiveTime { set; get; }
    //是否有效 不可赋值可以获取
    private Boolean _isEffective;
    public Boolean isEffective
    {
        //是否有效不能自主设置
        private set
        {
            _isEffective = value;
        }
        get
        {
            TimeSpan ts = DateTime.Now.Subtract(this.CreateTime);
            if (this.EffectiveTime <= ts)
            {
                this._isEffective = false;
            }
            else
            {
                this._isEffective = true;
            }
            return _isEffective;
        }
    }

    public VerificationCode()
    {
        //创建对象同时对创建时间和有效时间进行赋值
        CreateTime = DateTime.Now;
        EffectiveTime = TimeSpan.FromMinutes(2d);
    }
}

这个是验证方法了

 protected void btnVerification_Click(object sender, EventArgs e)
    {
        foreach (VerificationCode vc in vclist)
        {
            if (txtVerificationCode.Text == vc.Verificationcode)
            {
                if (vc.isEffective)
                {
                    MessageBox.Show("验证码核对正确", "消息提示", MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1, MessageBoxOptions.ServiceNotification);
                    return;
                }
                else
                {
                    MessageBox.Show("验证码已过期", "消息提示", MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1, MessageBoxOptions.ServiceNotification);
                    return;
                }
            }
        }
        MessageBox.Show("错误的验证码", "消息提示", MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1, MessageBoxOptions.ServiceNotification);
        txtVerificationCode.Text = "";
    }

    /// <summary>
    /// 根据62个数字和英文大小写生成随机的24位验证码
    /// </summary>
    /// <returns></returns>
    public VerificationCode GenerateVerificationCode()
    {
        StringBuilder VerificationCode = new StringBuilder();
        string AllVerificationCode = "0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,G,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z";
        string[] ArrayVerificationCode = AllVerificationCode.Split(',');
        Random SingleVerificationCode = new Random();
        for (int i = 0; i < 24; i++)
        {
            int Array_subscript = SingleVerificationCode.Next(ArrayVerificationCode.Length);
            VerificationCode = VerificationCode.Append(ArrayVerificationCode[Array_subscript]);
        }
        VerificationCode vc = new VerificationCode();
        vc.Verificationcode = VerificationCode.ToString();
        vclist.Add(vc);
        return vc;
    }

嗯,基本上就是这样了,邮箱有了,验证码有了,发送验证码不就简单了?ok,处理一下,可以交货了。

写在末尾的话

本来是不想写的,后来想了一下,反正没啥事,写写也不吃亏,凑点字数呗。这算是,第二次在CSDN发博客吧,只不过受到来自二哥(沉默的王二)的影响,觉得确实不能太懒,啥都不会,总归是不太好。看了不少二哥写的经历,确实,感觉二哥的境界绝对是我可望不可及的(毕竟没有看过那么多的书),不过,还是想追一追,万一呢?谈的优点远了,反正就是写一下嘛,就当是顺手笔记了,期待着能有强者在评论指教一番,还能获取一点意外之喜不是。
对了,顺手推荐一下二哥,沉默的王二,没看过的兄弟们看一下,自我感觉二哥的文章真的非常nice(读书人的文采绝不是我辈学渣可以相提并论的),还有我不是二哥的托,单纯的喜欢,不是那种喜欢(一个纯洁的微笑)。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值