验证用户的有效性或者安全性,是每一个系统必备的安全措施,在移动端优先的时代,利用手机验证码来验证用户,算是安全系数比较高的手段。放眼当下几乎全部的互联网应用几乎都开放了手机验证码登陆,并且应用内的敏感操做都须要手机验证码或者指纹,甚至面部识别来肯定当前操做人的权限。算法
抛开其余端,单就移动端App方式而言,若是用户频繁进行敏感操做,须要频繁发送验证码,其实在用户体验上并不友好,何况短信费用也随之增长。就App形式而言,验证一个用户的有效性其实能够演变为验证设备的有效性,即:当前人在当前设备上是否可信。设计模式
如下讨论只针对非Web(浏览器)环境,Web环境其实也能够根据浏览器的信息来生成一个相似设备标示的代码
不少系统在设计之初,就已经考虑到安全主设备的概念,就像微信,若是在同一个手机上打开是不须要每次都进行登陆操做的。进行设备验证是每一个安全系统比较重要的部分,推荐在系统设计之初就要考虑。回归正题,对于不少行业来讲,用户在App内频繁进行一些敏感操做是很正常的,好比我所在的在线教育行业,老师会很频繁的在一个班级内添加学生和老师(咱们认为这些操做属于敏感操做)。若是每次都须要老师发送验证码来进行操做,那交互上真的是太不友好。要想保证业务操做的安全性以及改善交互操做,咱们就须要抽象出问题的根本所在。浏览器
发送验证码操做最终的目的是为了验证操做人是操做人,听起来很绕是否是。实现这个最终目的,其实有不少解决方案,其中用户可信设备就属于其中一类,而手机验证码方式又是用户可信设备实现的一种方式,具体来讲有几点:安全
基于以上所说,系统设计的时候就能够抽象出一个用户可信设备中心,包括敏感操做的定义,可信设备的有效时长,可信设备的定义(好比:验证码经过的设备可定义为有效设备)等等概念。经过这样设计,短信验证只不过成为验证用户信任设备的一种途经,彻底能够作到和具体业务无关(敏感级别最高操做除外),通常敏感的操做业务接口也能够避免添加验证码参数,真正的把验证和业务相分离,岂不美哉?微信
通过这样抽象,用户可信设备中心其实本质的接口只有几个:数据结构
固然你的系统首先要有设备的概念,若是非要写几行代码的话架构
public async Task<int> CheckUserDevice(UserDeviceReq para) { if (para == null || string.IsNullOrWhiteSpace(para.DeviceName) || para.UserId <= 0) { return 0; } //检查签名 var sign = EncrypHelper.MD5Encrypt($"{SysConfig.SecretKey}_{para.UserId}_{para.DeviceName}"); if (sign != para.Sign) { return 0; } string key = $"{para.UserId}_{para.DeviceName}"; var authRet = await RedisClient.GetString(key); if (string.IsNullOrWhiteSpace(authRet)) { //告诉客户端须要短信验证码 return 414000; } return 1; }
public async Task<int> SetUserDevice(UserDeviceReq para) { if (para == null || string.IsNullOrWhiteSpace(para.DeviceName) || para.UserId <= 0) { return 0; } //检查签名 var sign = EncrypHelper.MD5Encrypt($"{SysConfig.SecretKey}_{para.UserId}_{para.DeviceName}"); if (sign != para.Sign) { return 0; } string key = $"{para.UserId}_{para.DeviceName}"; var cacheRet = await RedisClient.GetString(key); if (string.IsNullOrWhiteSpace(cacheRet)) { UserDeviceInfo value = new UserDeviceInfo() { UserId = para.UserId, DeviceName = para.DeviceName, OperationCode = para.OperationCode, CreateDate = DateTime.Now, Context = "" }; var userDeviceExp = SysConfig.GetAppSetting("Config:UserDeviceExpire"); if (string.IsNullOrWhiteSpace(userDeviceExp)) { userDeviceExp = "300"; } var authRet = await RedisClient.SetString(key, JsonConvert.SerializeObject(value), TimeSpan.FromMinutes(int.Parse(userDeviceExp))); if (!authRet) { return 0; } } return 1; }
更多精彩文章并发