public IActionResult VCodeCheck(VerifyInfoModel verifyInfo) { VCodeCheckResponseModel responseModel = null; // 获取ip地址 string userIp = _accessor.HttpContext.Connection.RemoteIpAddress.ToString(); responseModel = _service.VCodeCheck(verifyInfo, userIp); return(Ok(responseModel)); }
public IActionResult VCodeCheck(VerifyInfoModel verifyInfo) { VCodeCheckResponseModel responseModel = null; // appId 效验: 这通常需要你自己根据业务实现 IAppChecker AppCheckModel appCheckResult = _appChecker.CheckAppId(verifyInfo.AppId); if (!appCheckResult.Pass) { // -6 appId 效验不通过 -> 不允许验证, 提示错误信息 responseModel = new VCodeCheckResponseModel { code = -6, message = appCheckResult.Message }; return(Ok(responseModel)); } // 获取ip地址 string userIp = _accessor.HttpContext.Connection.RemoteIpAddress.ToString(); responseModel = _service.VCodeCheck(verifyInfo, userIp); return(Ok(responseModel)); }
public override async Task InvokeAsync(HttpContext context) { string inputBody; using (var reader = new System.IO.StreamReader( context.Request.Body, Encoding.UTF8)) { inputBody = await reader.ReadToEndAsync(); } VerifyInfoModel verifyInfo = _jsonHelper.Deserialize <VerifyInfoModel>(inputBody); // 获取ip地址 string userIp = _accessor.HttpContext.Connection.RemoteIpAddress.ToString(); VCodeCheckResponseModel responseModel = _service.VCodeCheck(verifyInfo, userIp); string responseJsonStr = _jsonHelper.Serialize(responseModel); context.Response.ContentType = "application/json"; await context.Response.WriteAsync(responseJsonStr, Encoding.UTF8); // Response.Write 开始, 不要再 Call next // Call the next delegate/middleware in the pipeline //await _next(context); }
public VCodeCheckResponseModel VCodeCheck(VerifyInfoModel verifyInfo, string userIp) { VCodeCheckResponseModel rtnResult = new VCodeCheckResponseModel(); // 允许的偏移量(点触容错) int allowOffset = 10; // appId 效验: 这通常需要你自己根据业务实现 IAppChecker #region AppId效验 AppCheckModel appCheckResult = AppChecker.CheckAppId(verifyInfo.AppId); if (!appCheckResult.Pass) { // -6 appId 效验不通过 -> 不允许验证, 提示错误信息 rtnResult = new VCodeCheckResponseModel { code = -6, message = appCheckResult.Message }; return(rtnResult); } #endregion #region 尝试从内存中取出对应的 VCodeKey // 获取此用户会话的验证码效验 vCodeKey string cacheKeyVCodeKey = CachePrefixVCodeKey + verifyInfo.UserId; if (!_cacheHelper.Exists(cacheKeyVCodeKey)) { // 验证码无效,1.此验证码已被销毁 rtnResult = new VCodeCheckResponseModel { code = -5, message = "验证码过期, 获取新验证码" }; return(rtnResult); } string rightVCodeKey = _cacheHelper.Get <string>(cacheKeyVCodeKey); // AES解密 string vCodeKeyJsonStr = _encryptHelper.Decrypt(rightVCodeKey, _options.EncryptKey); // json -> 对象 VCodeKeyModel vCodeKeyModel = null; try { // TODO: fixed: 临时修复, 直接将全部为0的字节去除, byte[] bytes = Encoding.UTF8.GetBytes(vCodeKeyJsonStr); byte[] remove0Bytes = bytes.Where(m => m != 0).ToArray(); string remove0ByteStr = Encoding.UTF8.GetString(remove0Bytes); // 能够转换为 对象, 则说明 vCodeKey 无误, 可以使用 //vCodeKeyModel = JsonHelper.Deserialize<VCodeKeyModel>(vCodeKeyJsonStr); vCodeKeyModel = JsonHelper.Deserialize <VCodeKeyModel>(remove0ByteStr); } catch (Exception ex) { // TODO: BUG: 经加密再解密后的jsonStr,虽然看起来一样,但发生了一点改变, 导致无法转换 // '0x00' is invalid after a single JSON value. Expected end of data. LineNumber: 0 | BytePositionInLine: 110. _logHelper?.Write(ex.ToString()); } if (vCodeKeyModel == null) { // 验证码无效,被篡改导致解密失败 rtnResult.code = -3; rtnResult.message = "验证码无效, 获取新验证码"; return(rtnResult); } #endregion #region 验证码是否过期 // 验证码是否过期 bool isExpired = ((DateTimeHelper.NowTimeStamp13() - vCodeKeyModel.TS) / 1000) > _options.ExpiredSec; if (isExpired) { // 验证码过期 rtnResult.code = -4; rtnResult.message = "验证码过期, 获取新验证码"; RemoveCacheVCodeKey(verifyInfo.UserId); return(rtnResult); } #endregion #region 效验点触位置数据 // 效验点触位置数据 IList <PointPosModel> rightVCodePos = vCodeKeyModel.VCodePos; IList <PointPosModel> userVCodePos = verifyInfo.VCodePos; // 验证码是否正确 bool isPass = false; if (userVCodePos.Count != rightVCodePos.Count) { // 验证不通过 isPass = false; } else { isPass = true; for (int i = 0; i < userVCodePos.Count; i++) { int xOffset = userVCodePos[i].X - rightVCodePos[i].X; int yOffset = userVCodePos[i].Y - rightVCodePos[i].Y; // x轴偏移量 xOffset = Math.Abs(xOffset); // y轴偏移量 yOffset = Math.Abs(yOffset); // 只要有一个点的任意一个轴偏移量大于allowOffset,则验证不通过 if (xOffset > allowOffset || yOffset > allowOffset) { isPass = false; } } } #endregion #region 未通过->错误次数达到上限? if (!isPass) { // 本次没通过验证 -> 错误次数+1 vCodeKeyModel.ErrorNum++; // 错误次数是否达上限 bool isMoreThanErrorNum = vCodeKeyModel.ErrorNum > _options.AllowErrorNum; if (isMoreThanErrorNum) { // 错误 -> 2.code:-2 验证码错误 且 错误次数已达上限 -> message: 这题有点难,为你换一个试试吧 rtnResult.code = -2; rtnResult.message = "这题有点难, 为你换一个试试吧"; RemoveCacheVCodeKey(verifyInfo.UserId); return(rtnResult); } else { // 错误 -> 1.code:-1 验证码错误 且 错误次数未达上限 -> message: 点错啦,请重试 string vCodekeyJsonStrTemp = JsonHelper.Serialize(vCodeKeyModel); // AES加密 vCodekeyJsonStrTemp string vCodeKeyStrTemp = _encryptHelper.Encrypt(vCodekeyJsonStrTemp, _options.EncryptKey); // 更新 Cache 中的 vCodeKey _cacheHelper.Insert <string>(CachePrefixVCodeKey + verifyInfo.UserId, vCodeKeyStrTemp); rtnResult.code = -1; rtnResult.message = "点错啦,请重试"; return(rtnResult); } } #endregion #region 验证通过->下发ticket // 正确 -> code:0 下发票据 ticket TicketModel ticketModel = new TicketModel { IP = userIp, IsPass = true, TS = DateTimeHelper.NowTimeStamp13() }; string ticketJsonStr = JsonHelper.Serialize(ticketModel); // 对 ticketJsonStr 加密 string ticket = _encryptHelper.Encrypt(ticketJsonStr, _options.EncryptKey); // 内存中存一份ticket, 用于效验 _cacheHelper.Insert <string>(CachePrefixTicket + verifyInfo.UserId, ticket); rtnResult.code = 0; rtnResult.message = "验证通过"; rtnResult.data = new VCodeCheckResponseModel.DataModel { appId = verifyInfo.AppId, ticket = ticket }; return(rtnResult); #endregion }