這篇文章主要介紹了MVC如何使用極驗驗證制作登錄驗證碼,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
“真誠服務(wù),讓網(wǎng)絡(luò)創(chuàng)造價值”是我們的服務(wù)理念,創(chuàng)新互聯(lián)團(tuán)隊十余年如一日始終堅持在網(wǎng)站建設(shè)領(lǐng)域,為客戶提供優(yōu)質(zhì)服。不管你處于什么行業(yè),助你輕松跨入“互聯(lián)網(wǎng)+”時代,PC網(wǎng)站+手機網(wǎng)站+公眾號+重慶小程序開發(fā)。在之前的項目中,如果有需要使用驗證碼,基本都是自己用GDI+畫圖出來,簡單好用,但是卻也存在了一些小問題,首先若較少干擾線,則安全性不是很高,驗證碼容易被機器識別,若多畫太多干擾線條,機器人識別率下降的同時,人眼的識別率也同步下降(震驚哭)。更為重要的是,GDI+繪制的驗證碼一般來說也不會很美觀,如果做一個炫酷的登陸界面卻配了這樣一個驗證碼,畫風(fēng)詭異,丑到極致。
再后來瀏覽網(wǎng)頁的過程中,發(fā)現(xiàn)很多很多網(wǎng)站項目中都使用了一種叫極驗驗證的驗證碼,采用移動滑塊的方式進(jìn)行驗證,方便美觀。而一番搜索之后了解到,官方提供的免費版也足以應(yīng)付我手頭的大多數(shù)項目了,不禁想把在MVC學(xué)習(xí)過程中試著使用極驗驗證來作為登錄的驗證碼。
極驗官方提供了C#的SDK和Demo供開發(fā)者參考,不過是Webform版本的,可讀性不是很高,而現(xiàn)在使用Webform進(jìn)行網(wǎng)站開發(fā)的也基本消失了,我將在官方Webform代碼的基礎(chǔ)上,將其用在ASP.NET MVC程序中。
注冊極驗
到極驗官網(wǎng)注冊賬號之后進(jìn)入后臺管理界面,點擊添加驗證
添加后我們可以得到ID和KEY
完成驗證邏輯
1. 首先我們需要引入官方的Geetestlib類
using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using System.Security.Cryptography; using System.Net; using System.IO; namespace PMS.WebApp.Models { ////// GeetestLib 極驗驗證C# SDK基本庫 /// public class GeetestLib { ////// SDK版本號 /// public const String version = "3.2.0"; ////// SDK開發(fā)語言 /// public const String sdkLang = "csharp"; ////// 極驗驗證API URL /// protected const String apiUrl = "http://api.geetest.com"; ////// register url /// protected const String registerUrl = "/register.php"; ////// validate url /// protected const String validateUrl = "/validate.php"; ////// 極驗驗證API服務(wù)狀態(tài)Session Key /// public const String gtServerStatusSessionKey = "gt_server_status"; ////// 極驗驗證二次驗證表單數(shù)據(jù) Chllenge /// public const String fnGeetestChallenge = "geetest_challenge"; ////// 極驗驗證二次驗證表單數(shù)據(jù) Validate /// public const String fnGeetestValidate = "geetest_validate"; ////// 極驗驗證二次驗證表單數(shù)據(jù) Seccode /// public const String fnGeetestSeccode = "geetest_seccode"; private String userID = ""; private String responseStr = ""; private String captchaID = ""; private String privateKey = ""; ////// 驗證成功結(jié)果字符串 /// public const int successResult = 1; ////// 證結(jié)失敗驗果字符串 /// public const int failResult = 0; ////// 判定為機器人結(jié)果字符串 /// public const String forbiddenResult = "forbidden"; ////// GeetestLib構(gòu)造函數(shù) /// /// 極驗驗證公鑰 /// 極驗驗證私鑰 public GeetestLib(String publicKey, String privateKey) { this.privateKey = privateKey; this.captchaID = publicKey; } private int getRandomNum() { Random rand =new Random(); int randRes = rand.Next(100); return randRes; } ////// 驗證初始化預(yù)處理 /// ///初始化結(jié)果 public Byte preProcess() { if (this.captchaID == null) { Console.WriteLine("publicKey is null!"); } else { String challenge = this.registerChallenge(); if (challenge.Length == 32) { this.getSuccessPreProcessRes(challenge); return 1; } else { this.getFailPreProcessRes(); Console.WriteLine("Server regist challenge failed!"); } } return 0; } public Byte preProcess(String userID) { if (this.captchaID == null) { Console.WriteLine("publicKey is null!"); } else { this.userID = userID; String challenge = this.registerChallenge(); if (challenge.Length == 32) { this.getSuccessPreProcessRes(challenge); return 1; } else { this.getFailPreProcessRes(); Console.WriteLine("Server regist challenge failed!"); } } return 0; } public String getResponseStr() { return this.responseStr; } ////// 預(yù)處理失敗后的返回格式串 /// private void getFailPreProcessRes() { int rand1 = this.getRandomNum(); int rand2 = this.getRandomNum(); String md5Str1 = this.md5Encode(rand1 + ""); String md5Str2 = this.md5Encode(rand2 + ""); String challenge = md5Str1 + md5Str2.Substring(0, 2); this.responseStr = "{" + string.Format( "\"success\":{0},\"gt\":\"{1}\",\"challenge\":\"{2}\"", 0, this.captchaID, challenge) + "}"; } ////// 預(yù)處理成功后的標(biāo)準(zhǔn)串 /// private void getSuccessPreProcessRes(String challenge) { challenge = this.md5Encode(challenge + this.privateKey); this.responseStr ="{" + string.Format( "\"success\":{0},\"gt\":\"{1}\",\"challenge\":\"{2}\"", 1, this.captchaID, challenge) + "}"; } ////// failback模式的驗證方式 /// /// failback模式下用于與validate一起解碼答案, 判斷驗證是否正確 /// failback模式下用于與challenge一起解碼答案, 判斷驗證是否正確 /// failback模式下,其實是個沒用的參數(shù) ///驗證結(jié)果 public int failbackValidateRequest(String challenge, String validate, String seccode) { if (!this.requestIsLegal(challenge, validate, seccode)) return GeetestLib.failResult; String[] validateStr = validate.Split('_'); String encodeAns = validateStr[0]; String encodeFullBgImgIndex = validateStr[1]; String encodeImgGrpIndex = validateStr[2]; int decodeAns = this.decodeResponse(challenge, encodeAns); int decodeFullBgImgIndex = this.decodeResponse(challenge, encodeFullBgImgIndex); int decodeImgGrpIndex = this.decodeResponse(challenge, encodeImgGrpIndex); int validateResult = this.validateFailImage(decodeAns, decodeFullBgImgIndex, decodeImgGrpIndex); return validateResult; } private int validateFailImage(int ans, int full_bg_index, int img_grp_index) { const int thread = 3; String full_bg_name = this.md5Encode(full_bg_index + "").Substring(0, 10); String bg_name = md5Encode(img_grp_index + "").Substring(10, 10); String answer_decode = ""; for (int i = 0;i < 9; i++) { if (i % 2 == 0) answer_decode += full_bg_name.ElementAt(i); else if (i % 2 == 1) answer_decode += bg_name.ElementAt(i); } String x_decode = answer_decode.Substring(4); int x_int = Convert.ToInt32(x_decode, 16); int result = x_int % 200; if (result < 40) result = 40; if (Math.Abs(ans - result) < thread) return GeetestLib.successResult; else return GeetestLib.failResult; } private Boolean requestIsLegal(String challenge, String validate, String seccode) { if (challenge.Equals(string.Empty) || validate.Equals(string.Empty) || seccode.Equals(string.Empty)) return false; return true; } ////// 向gt-server進(jìn)行二次驗證 /// /// 本次驗證會話的標(biāo)識 /// 拖動完成后server端返回的驗證結(jié)果標(biāo)識字符串 /// 驗證結(jié)果的校驗碼,如果gt-server返回的不與這個值相等則表明驗證失敗 ///二次驗證結(jié)果 public int enhencedValidateRequest(String challenge, String validate, String seccode) { if (!this.requestIsLegal(challenge, validate, seccode)) return GeetestLib.failResult; if (validate.Length > 0 && checkResultByPrivate(challenge, validate)) { String query = "seccode=" + seccode + "&sdk=csharp_" + GeetestLib.version; String response = ""; try { response = postValidate(query); } catch (Exception e) { Console.WriteLine(e); } if (response.Equals(md5Encode(seccode))) { return GeetestLib.successResult; } } return GeetestLib.failResult; } public int enhencedValidateRequest(String challenge, String validate, String seccode, String userID) { if (!this.requestIsLegal(challenge, validate, seccode)) return GeetestLib.failResult; if (validate.Length > 0 && checkResultByPrivate(challenge, validate)) { String query = "seccode=" + seccode + "&user_id=" + userID + "&sdk=csharp_" + GeetestLib.version; String response = ""; try { response = postValidate(query); } catch (Exception e) { Console.WriteLine(e); } if (response.Equals(md5Encode(seccode))) { return GeetestLib.successResult; } } return GeetestLib.failResult; } private String readContentFromGet(String url) { try { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); request.Timeout = 20000; HttpWebResponse response = (HttpWebResponse)request.GetResponse(); Stream myResponseStream = response.GetResponseStream(); StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("utf-8")); String retString = myStreamReader.ReadToEnd(); myStreamReader.Close(); myResponseStream.Close(); return retString; } catch { return ""; } } private String registerChallenge() { String url = ""; if (string.Empty.Equals(this.userID)) { url = string.Format("{0}{1}?gt={2}", GeetestLib.apiUrl, GeetestLib.registerUrl, this.captchaID); } else { url = string.Format("{0}{1}?gt={2}&user_id={3}", GeetestLib.apiUrl, GeetestLib.registerUrl, this.captchaID, this.userID); } string retString = this.readContentFromGet(url); return retString; } private Boolean checkResultByPrivate(String origin, String validate) { String encodeStr = md5Encode(privateKey + "geetest" + origin); return validate.Equals(encodeStr); } private String postValidate(String data) { String url = string.Format("{0}{1}", GeetestLib.apiUrl, GeetestLib.validateUrl); HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); request.Method = "POST"; request.ContentType = "application/x-www-form-urlencoded"; request.ContentLength = Encoding.UTF8.GetByteCount(data); // 發(fā)送數(shù)據(jù) Stream myRequestStream = request.GetRequestStream(); byte[] requestBytes = System.Text.Encoding.ASCII.GetBytes(data); myRequestStream.Write(requestBytes, 0, requestBytes.Length); myRequestStream.Close(); HttpWebResponse response = (HttpWebResponse)request.GetResponse(); // 讀取返回信息 Stream myResponseStream = response.GetResponseStream(); StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("utf-8")); string retString = myStreamReader.ReadToEnd(); myStreamReader.Close(); myResponseStream.Close(); return retString; } private int decodeRandBase(String challenge) { String baseStr = challenge.Substring(32, 2); ListtempList = new List (); for(int i = 0; i < baseStr.Length; i++) { int tempAscii = (int)baseStr[i]; tempList.Add((tempAscii > 57) ? (tempAscii - 87) : (tempAscii - 48)); } int result = tempList.ElementAt(0) * 36 + tempList.ElementAt(1); return result; } private int decodeResponse(String challenge, String str) { if (str.Length>100) return 0; int[] shuzi = new int[] { 1, 2, 5, 10, 50}; String chongfu = ""; Hashtable key = new Hashtable(); int count = 0; for (int i=0;i 2. 獲取驗證碼
引入Jquery庫
添加用于放置驗證碼的div(需要放到form表單中)
添加JS代碼用于獲取驗證碼processGeeTest方法中我們異步請求的地址“/Login/GeekTest”就是獲取驗證碼是后臺需要執(zhí)行的方法
public ActionResult GeekTest() { return Content(GetCaptcha(),"application/json"); } private string GetCaptcha() { var geetest = new GeetestLib("3594e0d834df77cedc7351a02b5b06a4", "b961c8081ce88af7e32a3f45d00dff84"); var gtServerStatus = geetest.preProcess(); Session[GeetestLib.gtServerStatusSessionKey] = gtServerStatus; return geetest.getResponseStr(); }3. 校驗驗證碼
注意,當(dāng)提交form表單時,會將三個和極驗有關(guān)的參數(shù)傳到后臺方法(geetest_challenge、geetest_validate、geetest_seccode),若驗證碼未驗證成功,則參數(shù)為空值。
后臺驗證方法為:
private bool CheckGeeTestResult() { var geetest = new GeetestLib("3594e0d834df77cedc7351a02b5b06a4", "b961c8081ce88af7e32a3f45d00dff84 "); var gtServerStatusCode = (byte)Session[GeetestLib.gtServerStatusSessionKey]; var userId = (string)Session["userID"]; 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, userId) : geetest.failbackValidateRequest(challenge, validate, seccode); return result == 1; }我們可以在表單中判斷驗證碼是否成功校驗:
public ActionResult Login() { if (!CheckGeeTestResult()) return Content("no:請先完成驗證操作。"); .... }感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“MVC如何使用極驗驗證制作登錄驗證碼”這篇文章對大家有幫助,同時也希望大家多多支持創(chuàng)新互聯(lián)網(wǎng)站建設(shè)公司,,關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,更多相關(guān)知識等著你來學(xué)習(xí)!
網(wǎng)頁標(biāo)題:MVC如何使用極驗驗證制作登錄驗證碼-創(chuàng)新互聯(lián)
鏈接分享:http://weahome.cn/article/dgpjsi.html