Example #1
0
        public IActionResult VCodeCheck(VerifyInfoModel verifyInfo)
        {
            VCodeCheckResponseModel responseModel = null;

            // 获取ip地址
            string userIp = _accessor.HttpContext.Connection.RemoteIpAddress.ToString();

            responseModel = _service.VCodeCheck(verifyInfo, userIp);

            return(Ok(responseModel));
        }
Example #2
0
        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);
        }
Example #4
0
        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
        }