1. 程式人生 > >MVC5使用Geetest極驗驗證碼示例

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>

執行結果如圖:

這裡寫圖片描述