MVC5使用Geetest极验验证码示例

Models文件夹实体类

LoginInfo.cs

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;

namespace MvcDemo.Models.Geetest
{
    public class LoginInfo
    {
        [Required(ErrorMessage="用户名不能为空")]
        public string UserName { get; set; }

        [Required(ErrorMessage = "密码不能为空")]
        public string Password { get; set; }
    }
}

GeetestConfig.cs

using System;

namespace MvcDemo.Models.Geetest
{
    public class GeetestConfig
    {
        /// <summary>
        /// 验证ID
        /// </summary>
        public const string PublicKey = "6ef7c61ac11117de6996efa65be1c27e";

        /// <summary>
        /// 验证Key
        /// </summary>
        public const string PrivateKey = "62add4e324dd9e9ef2ea35192f8d9181";
    }
}

GeetestLib.cs

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;

namespace MvcDemo.Models.Geetest
{
    /// <summary>
    ///     GeetestLib 极验验证C# SDK基本库
    /// </summary>
    public class GeetestLib
    {
        /// <summary>
        ///     SDK版本号
        /// </summary>
        public const string Version = "3.1.1";

        /// <summary>
        ///     SDK开发语言
        /// </summary>
        public const string SdkLang = "csharp";

        /// <summary>
        ///     极验验证API URL
        /// </summary>
        protected const string ApiUrl = "http://api.geetest.com";

        /// <summary>
        ///     register url
        /// </summary>
        protected const string RegisterUrl = "/register.php";

        /// <summary>
        ///     validate url
        /// </summary>
        protected const string ValidateUrl = "/validate.php";

        /// <summary>
        ///     极验验证API服务状态Session Key
        /// </summary>
        public const string GtServerStatusSessionKey = "gt_server_status";

        /// <summary>
        ///     极验验证二次验证表单数据 Chllenge
        /// </summary>
        public const string FnGeetestChallenge = "geetest_challenge";

        /// <summary>
        ///     极验验证二次验证表单数据 Validate
        /// </summary>
        public const string FnGeetestValidate = "geetest_validate";

        /// <summary>
        ///     极验验证二次验证表单数据 Seccode
        /// </summary>
        public const string FnGeetestSeccode = "geetest_seccode";

        /// <summary>
        ///     验证成功结果字符串
        /// </summary>
        public const int SuccessResult = 1;

        /// <summary>
        ///     证结失败验果字符串
        /// </summary>
        public const int FailResult = 0;

        /// <summary>
        ///     判定为机器人结果字符串
        /// </summary>
        public const string ForbiddenResult = "forbidden";

        private readonly string captchaID = "";
        private readonly string privateKey = "";
        private string responseStr = "";

        /// <summary>
        ///     GeetestLib构造函数
        /// </summary>
        /// <param name="publicKey">极验验证公钥</param>
        /// <param name="privateKey">极验验证私钥</param>
        public GeetestLib(string publicKey, string privateKey)
        {
            this.privateKey = privateKey;
            captchaID = publicKey;
        }

        private int GetRandomNum()
        {
            var rand = new Random();
            var randRes = rand.Next(100);
            return randRes;
        }

        /// <summary>
        ///     验证初始化预处理
        /// </summary>
        /// <returns>初始化结果</returns>
        public byte PreProcess()
        {
            if (captchaID == null)
            {
                Console.WriteLine("publicKey is null!");
            }
            else
            {
                var challenge = RegisterChallenge();
                if (challenge.Length == 32)
                {
                    GetSuccessPreProcessRes(challenge);
                    return 1;
                }
                GetFailPreProcessRes();
                Console.WriteLine("Server regist challenge failed!");
            }

            return 0;
        }

        public string GetResponseStr()
        {
            return responseStr;
        }

        /// <summary>
        ///     预处理失败后的返回格式串
        /// </summary>
        private void GetFailPreProcessRes()
        {
            var rand1 = GetRandomNum();
            var rand2 = GetRandomNum();
            var md5Str1 = md5Encode(rand1 + "");
            var md5Str2 = md5Encode(rand2 + "");
            var challenge = md5Str1 + md5Str2.Substring(0, 2);
            responseStr = "{" + string.Format("\"success\":{0},\"gt\":\"{1}\",\"challenge\":\"{2}\"", 0, captchaID, challenge) + "}";
        }

        /// <summary>
        ///     预处理成功后的标准串
        /// </summary>
        private void GetSuccessPreProcessRes(string challenge)
        {
            challenge = md5Encode(challenge + privateKey);
            responseStr = "{" + string.Format("\"success\":{0},\"gt\":\"{1}\",\"challenge\":\"{2}\"", 1, captchaID, challenge) + "}";
        }

        /// <summary>
        ///     failback模式的验证方式
        /// </summary>
        /// <param name="challenge">failback模式下用于与validate一起解码答案, 判断验证是否正确</param>
        /// <param name="validate">failback模式下用于与challenge一起解码答案, 判断验证是否正确</param>
        /// <param name="seccode">failback模式下,其实是个没用的参数</param>
        /// <returns>验证结果</returns>
        public int FailbackValidateRequest(string challenge, string validate, string seccode)
        {
            if (!RequestIsLegal(challenge, validate, seccode)) return FailResult;
            var validateStr = validate.Split('_');
            var encodeAns = validateStr[0];
            var encodeFullBgImgIndex = validateStr[1];
            var encodeImgGrpIndex = validateStr[2];
            var decodeAns = DecodeResponse(challenge, encodeAns);
            var decodeFullBgImgIndex = DecodeResponse(challenge, encodeFullBgImgIndex);
            var decodeImgGrpIndex = DecodeResponse(challenge, encodeImgGrpIndex);
            var validateResult = ValidateFailImage(decodeAns, decodeFullBgImgIndex, decodeImgGrpIndex);
            return validateResult;
        }

        private int ValidateFailImage(int ans, int full_bg_index, int img_grp_index)
        {
            const int thread = 3;
            var fullBgName = md5Encode(full_bg_index + "").Substring(0, 10);
            var bgName = md5Encode(img_grp_index + "").Substring(10, 10);
            var answerDecode = "";
            for (var i = 0; i < 9; i++)
            {
                switch (i % 2)
                {
                    case 0:
                        answerDecode += fullBgName.ElementAt(i);
                        break;
                    case 1:
                        answerDecode += bgName.ElementAt(i);
                        break;
                }
            }
            var xDecode = answerDecode.Substring(4);
            var xInt = Convert.ToInt32(xDecode, 16);
            var result = xInt % 200;
            if (result < 40) result = 40;
            return Math.Abs(ans - result) < thread ? SuccessResult : FailResult;
        }

        private bool RequestIsLegal(string challenge, string validate, string seccode)
        {
            return !challenge.Equals(string.Empty) && !validate.Equals(string.Empty) && !seccode.Equals(string.Empty);
        }

        /// <summary>
        ///     向gt-server进行二次验证
        /// </summary>
        /// <param name="challenge">本次验证会话的唯一标识</param>
        /// <param name="validate">拖动完成后server端返回的验证结果标识字符串</param>
        /// <param name="seccode">验证结果的校验码,如果gt-server返回的不与这个值相等则表明验证失败</param>
        /// <returns>二次验证结果</returns>
        public int EnhencedValidateRequest(string challenge, string validate, string seccode)
        {
            if (!RequestIsLegal(challenge, validate, seccode)) return FailResult;
            if (validate.Length <= 0 || !CheckResultByPrivate(challenge, validate)) return FailResult;
            var query = "seccode=" + seccode + "&sdk=csharp_" + Version;
            var response = "";
            try
            {
                response = PostValidate(query);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
            return response.Equals(md5Encode(seccode)) ? SuccessResult : FailResult;
        }

        private string ReadContentFromGet(string url)
        {
            try
            {
                var request = (HttpWebRequest)WebRequest.Create(url);
                request.Timeout = 20000;
                var response = (HttpWebResponse)request.GetResponse();
                var myResponseStream = response.GetResponseStream();
                var myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("utf-8"));
                var retstring = myStreamReader.ReadToEnd();
                myStreamReader.Close();
                myResponseStream.Close();
                return retstring;
            }
            catch
            {
                return "";
            }
        }

        private string RegisterChallenge()
        {
            var url = string.Format("{0}{1}?gt={2}", ApiUrl, RegisterUrl, captchaID);
            var retstring = ReadContentFromGet(url);
            return retstring;
        }

        private bool CheckResultByPrivate(string origin, string validate)
        {
            var encodeStr = md5Encode(privateKey + "geetest" + origin);
            return validate.Equals(encodeStr);
        }

        private string PostValidate(string data)
        {
            var url = string.Format("{0}{1}", ApiUrl, ValidateUrl);
            var request = (HttpWebRequest)WebRequest.Create(url);
            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";
            request.ContentLength = Encoding.UTF8.GetByteCount(data);
            // 发送数据
            var myRequestStream = request.GetRequestStream();
            var requestBytes = Encoding.ASCII.GetBytes(data);
            myRequestStream.Write(requestBytes, 0, requestBytes.Length);
            myRequestStream.Close();

            var response = (HttpWebResponse)request.GetResponse();
            // 读取返回信息
            var myResponseStream = response.GetResponseStream();
            var myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("utf-8"));
            var retstring = myStreamReader.ReadToEnd();
            myStreamReader.Close();
            myResponseStream.Close();

            return retstring;
        }

        private int DecodeRandBase(string challenge)
        {
            var baseStr = challenge.Substring(32, 2);
            var tempList = new List<int>();
            for (var i = 0; i < baseStr.Length; i++)
            {
                var tempAscii = (int)baseStr[i];
                tempList.Add((tempAscii > 57)
                    ? (tempAscii - 87)
                    : (tempAscii - 48));
            }
            var result = tempList.ElementAt(0) * 36 + tempList.ElementAt(1);
            return result;
        }

        private int DecodeResponse(string challenge, string str)
        {
            if (str.Length > 100) return 0;
            var shuzi = new[] { 1, 2, 5, 10, 50 };
            var chongfu = "";
            var key = new Hashtable();
            var count = 0;
            for (var i = 0; i < challenge.Length; i++)
            {
                var item = challenge.ElementAt(i) + "";
                if (chongfu.Contains(item)) continue;
                var value = shuzi[count % 5];
                chongfu += item;
                count++;
                key.Add(item, value);
            }
            var res = 0;
            for (var i = 0; i < str.Length; i++) res += (int)key[str[i] + ""];
            res = res - DecodeRandBase(challenge);
            return res;
        }

        private string md5Encode(string plainText)
        {
            var md5 = new MD5CryptoServiceProvider();
            var t2 = BitConverter.ToString(md5.ComputeHash(Encoding.Default.GetBytes(plainText)));
            t2 = t2.Replace("-", "");
            t2 = t2.ToLower();
            return t2;
        }
    }
}

控制器层

GeetestController.cs

using System.Web.Mvc;
using MvcDemo.Models.Geetest;

namespace MvcDemo.Controllers
{
    public class GeetestController : Controller
    {
        public ActionResult Geetest()
        {
            var loginInfo = new LoginInfo();
            return View(loginInfo);
        }

        [HttpPost]
        public ActionResult Geetest(LoginInfo loginInfo)
        {
            if (!ModelState.IsValid)
            {
                ViewData["message"] = "请填写完整数据";
                return View(loginInfo);
            }
            if (!IsVerifyCaptcha())
            {
                ViewData["message"] = "验证码错误";
                return View(loginInfo);
            }
            if (loginInfo.UserName == "admin" && loginInfo.Password == "123123")
            {
                ViewData["message"] = "登录成功";
                return View(loginInfo);
            }
            ViewData["message"] = "用户名密码错误";
            return View(loginInfo);
        }

        /// <summary>
        ///     验证码是否正确
        /// </summary>
        /// <returns></returns>
        public bool IsVerifyCaptcha()
        {
            var geetest = new GeetestLib(GeetestConfig.PublicKey, GeetestConfig.PrivateKey);
            var gtServerStatusCode = (byte) Session[GeetestLib.GtServerStatusSessionKey];
            var challenge = Request.Form.Get(GeetestLib.FnGeetestChallenge);
            var validate = Request.Form.Get(GeetestLib.FnGeetestValidate);
            var seccode = Request.Form.Get(GeetestLib.FnGeetestSeccode);
            var result = gtServerStatusCode == 1
                ? geetest.EnhencedValidateRequest(challenge, validate, seccode)
                : geetest.FailbackValidateRequest(challenge, validate, seccode);
            return result == 1;
        }

        /// <summary>
        ///     获取验证码
        /// </summary>
        /// <returns></returns>
        public ContentResult GetCaptcha()
        {
            var geetest = new GeetestLib(GeetestConfig.PublicKey, GeetestConfig.PrivateKey);
            var gtServerStatus = geetest.PreProcess();
            Session[GeetestLib.GtServerStatusSessionKey] = gtServerStatus;
            return Content(geetest.GetResponseStr());
        }
    }
}

Geetest.cshtml

@model MvcDemo.Models.Geetest.LoginInfo
@{
    ViewBag.Title = "Geetest";
    <script src="~/Scripts/jquery-1.10.2.min.js"></script>
    <script src="http://static.geetest.com/static/tools/gt.js"></script>
}

<form class="form-signin" action="@Url.Action("Geetest", "Geetest")" method="post">
    <h2 class="form-signin-heading">Please sign in</h2>
    @if (ViewData["message"] != null)
    {
        <div class="alert alert-danger alert-dismissible" role="alert">
            <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
            @ViewData["message"].ToString()
        </div>
    }
    <label>用户名</label>
    @Html.TextBoxFor(n => n.UserName, new { placeholder = "用户名", @class = "form-control", autofocus = "" })
    @Html.ValidationMessageFor(n => n.UserName)
    <br />
    <label>密码</label>
    @Html.PasswordFor(n => n.Password, new { placeholder = "密码", @class = "form-control" })
    @Html.ValidationMessageFor(n => n.Password)
    <br />
    <label for="captcha">验证码</label>
    <div id="captcha"></div>
    <br />
    <button type="submit" class="btn btn-lg btn-primary">提交</button>
</form>


<script>
    $.ajax({
        // 获取id,challenge,success(是否启用failback)
        url: '@Url.Action("GetCaptcha", "Geetest")',
        type: "get",
        dataType: "json", // 使用jsonp格式
        success: function (data) {
            // 使用initGeetest接口
            // 参数1:配置参数,与创建Geetest实例时接受的参数一致
            // 参数2:回调,回调的第一个参数验证码对象,之后可以使用它做appendTo之类的事件
            window.initGeetest({
                gt: data.gt,
                challenge: data.challenge,
                //product: "embed", // 产品形式
                offline: !data.success
            }, function (captchaObj) {
                // 将验证码加到id为captcha的元素里
                captchaObj.appendTo("#captcha");
            });
        }
    });
</script>

运行结果如图:

这里写图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值