net 写的app 接口,短信验证码模块的时候,本来验证码是放在session里面的,但是发现第二次会话时,愣是找不到这个验证码。于是查了下资料,不能放在session,更改为放在数据库。
要求:
1.验证码在一段时间内有效,过期无效
2.验证码发送不能太频繁,在一定时间内不能再发送多次。虽然这个app客户端可以限制,但是也会很容易被人抓包。恶意。。。
3.数据库的这张表不能无限的增长数据,要有合理的机制。。。
表结构
if OBJECT_ID ('MJC_Validate') is not null
drop table MJC_Validate
GO
create table [dbo].[MJC_Validate](
ValidateId int identity(1,1) not null, --id
Users_Tel nvarchar(20) not null default'', --用户手机
Validate nvarchar(6) not null default '', --验证码
Send_Time datetime not null default(getdate()), --发送时间
Valid_time datetime not null default(getdate()), --过期时间
Valid_Length int not null default(180), --有效期长度(秒)
--防止频繁操作
Interval_Length int not null default(60), --间隔长度(秒)
Interval_Time datetime not null default(getdate()), --间隔期
constraint [MJC_Validate_ValidateId] primary key (ValidateId asc)
)
controller 接口
/// <summary>
/// 验证码 注册和手机号登录都需要 获取验证码
/// </summary>
/// <returns></returns>
[HttpGet]
public JsonResult check_validate(string tel)
{
try
{
if (!Helper.IsTelephone(tel))
{
log.Info("手机号非法");
return Json(new { result = 1 }, JsonRequestBehavior.AllowGet);
}
string code = Helper.GetNumPwd(6);
#region 发送验证码
ITopClient client = new DefaultTopClient("http://gw.api.taobao.com/router/rest", "23302987", "b74ddcb3540ab637c90cf2ad59c22f1b");
AlibabaAliqinFcSmsNumSendRequest req = new AlibabaAliqinFcSmsNumSendRequest();
req.Extend = "";
req.SmsType = "normal";
req.SmsFreeSignName = "茗家春茶";
//req.SmsParam = "{'code':'963740','product':'alidayu'}";
req.SmsParam = "{'code':'" + code + "'}";
req.RecNum = tel;
req.SmsTemplateCode = "SMS_4915099";//短信模板
AlibabaAliqinFcSmsNumSendResponse rsp = client.Execute(req);
#endregion
//将短信验证码存放到数据库
//30 是验证码有效期,20 是验证码频繁期 单位都是秒
if (_ivalidate.create_code(tel, code, 30, 20))
{
string result = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(code, "MD5").ToLower();
//验证码已发送到您的手机请耐心等待
return Json(new { result = 2 }, JsonRequestBehavior.AllowGet);
//return Json(new { result = code }, JsonRequestBehavior.AllowGet);
}
else
{
log.Info("操作频繁,稍后再试,");
return Json(new { result = 3 }, JsonRequestBehavior.AllowGet);
}
}
catch (Exception e)
{
log.Info("报错", e);
return Json(new { result = 500 }, JsonRequestBehavior.AllowGet);
}
}
/// <summary>
/// 查询验证码
/// </summary>
/// <param name="code"></param>
/// <param name="tel"></param>
/// <returns></returns>
public JsonResult query_code(string code, string tel)
{
if (_ivalidate.query(tel, code))
return Json(new { result = true }, JsonRequestBehavior.AllowGet);
else
return Json(new { result = false }, JsonRequestBehavior.AllowGet);
}
这里就不写interface了
ValidateService
/// <summary>
/// 记录验证码
/// </summary>
/// <param name="tel"></param>
/// <param name="code"></param>
/// <returns></returns>
public bool create_code(string tel, string code, int ValidLength, int IntervalLength)
{
using (GeContext context = new GeContext(Utility.GetSqlConnectingString()))
{
try
{
DateTime now = DateTime.Now;
// 手机号是否存在
var _telModel = context.Ge_Validates.Where(p => p.Users_Tel == tel).OrderByDescending(p => p.ValidateId).ToList();
if (_telModel.Count > 1)
{
log.Info("该手机号存在多条验证码");
return false;
}
if (_telModel.Count > 0)
{
var telModel = _telModel.FirstOrDefault();
//是否过期
if (telModel.Valid_time < now)
{
//过期
context.Ge_Validates.Remove(telModel);
int re = context.SaveChanges();
if (re == 1)
{
if (create(tel, code, ValidLength, IntervalLength))
{
return true;
}
else
{
return false;
}
}
else
{
log.Info("删除失败");
return false;
}
}
else
{ //是否频繁
if (telModel.Interval_Time < now)
{
//不频繁
context.Ge_Validates.Remove(telModel);
int re = context.SaveChanges();
if (re == 1)
{
if (create(tel, code, ValidLength, IntervalLength))
{
return true;
}
else
{
return false;
}
}
else
{
log.Info("删除失败");
return false;
}
}
else
{
//频繁
log.Info("频繁");
return false;
}
}
}
else
{
log.Info("手机号" + tel + "不存在,直接创建");
if (create(tel, code, ValidLength, IntervalLength))
{
return true;
}
else
{
return false;
}
}
}
catch (Exception e)
{
log.Info(e.Message);
return false;
}
}
}
public bool create(string tel, string code, int ValidLength, int IntervalLength)
{
using (GeContext context = new GeContext(Utility.GetSqlConnectingString()))
{
try
{
DateTime now = DateTime.Now;
var validateModel = new Ge_ValidateModels
{
Users_Tel = tel,
Validate = code,
Send_Time = now,
Valid_Length = ValidLength,
Valid_time = now.AddSeconds(ValidLength),
Interval_Length = IntervalLength,
Interval_Time = now.AddSeconds(IntervalLength)
};
context.Ge_Validates.Add(validateModel);
int re = context.SaveChanges();
if (re == 1)
return true;
else
return false;
}
catch (Exception e)
{
log.Info(e.Message);
return false;
}
}
}
/// <summary>
/// 查询验证码
/// </summary>
/// <param name="tel"></param>
/// <param name="code"></param>
/// <returns></returns>
public bool query(string tel, string code)
{
using (GeContext context = new GeContext(Utility.GetSqlConnectingString()))
{
try
{
var validateModel = context.Ge_Validates.AsNoTracking().Where(p => p.Validate == code && p.Users_Tel == tel).OrderByDescending(p => p.ValidateId).FirstOrDefault();
if (validateModel != null)
{
if (validateModel.Valid_time < DateTime.Now)
{ //超时
log.Info("验证码:" + code + "过期");
return false;
}
else
{
return true;
}
}
else
{
log.Info("没有与手机号:" + tel + "相对应的验证码:" + code);
return false;
}
}
catch (Exception e)
{
log.Info(e.Message);
return false;
}
}
}
ok 到这步,完成。但是程序跑起来数据库还留有一些数据怎么办。不用担心,每个手机号只能留一条记录,存的是上一次的,新发一条验证码,自然会把现有的数据给覆盖。
PS:我用第三方短信平台是 阿里大鱼 0.045/条